diff --git a/.gitignore b/.gitignore index ce2538f..2810727 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ result .direnv .vscode/* -!.vscode/settings.json \ No newline at end of file +!.vscode/settings.json +nixos.qcow2 diff --git a/.hooks/post-commit b/.hooks/post-commit index 56c439d..03a160d 100755 --- a/.hooks/post-commit +++ b/.hooks/post-commit @@ -3,4 +3,12 @@ echo "restoring stashed changes" -git stash pop -q +# Find the most recent pre-commit stash and restore it +recent_stash=$(git stash list | grep "pre-commit-stash-" | head -n 1 | cut -d: -f1) + +if [ -n "$recent_stash" ]; then + echo "Found recent pre-commit stash: $recent_stash" + git stash pop -q "$recent_stash" +else + echo "No pre-commit stash found to restore" +fi diff --git a/.hooks/post-merge b/.hooks/post-merge index 11fb20c..06fabc3 100755 --- a/.hooks/post-merge +++ b/.hooks/post-merge @@ -4,14 +4,28 @@ # Get current branch name current_branch=$(git branch --show-current) -# Only restore stash if we're on main branch and a merge just completed +# Only perform actions if we're on main branch and a merge just completed if [ "$current_branch" = "main" ]; then - # Check if there are any stashes to restore - if git stash list | grep -q "stash@"; then - echo "Post-merge: restoring stashed changes on main branch" - git stash pop -q + echo "Post-merge on main branch - running nix flake check" + + # Run nix flake check after merge into main + nix flake check + + if [ ! $? -eq 0 ]; then + echo "Warning: nix flake check failed after merge into main" + echo "Please fix the issues as soon as possible" else - echo "Post-merge: no stash to restore on main branch" + echo "nix flake check passed after merge" + fi + + # Check if there are any pre-commit stashes to restore + recent_stash=$(git stash list | grep "pre-commit-stash-" | head -n 1 | cut -d: -f1) + + if [ -n "$recent_stash" ]; then + echo "Post-merge: restoring pre-commit stash on main branch" + git stash pop -q "$recent_stash" + else + echo "Post-merge: no pre-commit stash to restore on main branch" fi else echo "Post-merge: no action needed on branch '$current_branch'" diff --git a/.hooks/pre-commit b/.hooks/pre-commit index f98c64f..74cbc64 100755 --- a/.hooks/pre-commit +++ b/.hooks/pre-commit @@ -1,14 +1,24 @@ #!/usr/bin/env nix-shell #! nix-shell -i bash ../shell.nix -echo "stashing all uncommitted changes" -git stash -q --keep-index +# Get current branch name +current_branch=$(git branch --show-current) -echo "checking flakes all compile" -nix flake check +echo "stashing all uncommitted changes with named stash (excluding hooks)" +git stash push -q --keep-index -m "pre-commit-stash-$(date +%s)" -- ':!.hooks/' -if [ ! $? -eq 0 ]; then - exit 1 +# Only run nix flake check if we're on main branch +if [ "$current_branch" = "main" ]; then + echo "On main branch - checking flakes all compile" + nix flake check + + if [ ! $? -eq 0 ]; then + echo "Error: nix flake check failed on main branch" + exit 1 + fi + echo "nix flake check passed" +else + echo "Not on main branch - skipping nix flake check" fi echo "running linter" @@ -19,4 +29,4 @@ RESULT=$? echo "adding lint changes to commit" git add -u -exit $RESULT \ No newline at end of file +exit $RESULT diff --git a/.hooks/pre-merge-commit b/.hooks/pre-merge-commit index 9edaf92..9b7b41d 100755 --- a/.hooks/pre-merge-commit +++ b/.hooks/pre-merge-commit @@ -17,8 +17,8 @@ fi if [ "$target_branch" = "main" ]; then echo "Merging into main branch - running nix flake check..." - echo "stashing all uncommitted changes" - git stash -q --keep-index + echo "stashing all uncommitted changes with named stash (excluding hooks)" + git stash push -q --keep-index -m "pre-merge-stash-$(date +%s)" -- ':!.hooks/' echo "checking flakes all compile" nix flake check diff --git a/README.md b/README.md index f8c7ecf..d29ba58 100644 --- a/README.md +++ b/README.md @@ -43,17 +43,34 @@ nix multi user, multi system, configuration with `sops` secret management, `home - Look into this for auto rotating sops keys `https://technotim.live/posts/rotate-sops-encryption-keys/` - Look into this for npins https://jade.fyi/blog/pinning-nixos-with-npins/ - https://nixos-and-flakes.thiscute.world/ +- proton mail now has an smtp server we could use that for our zfs and SMART test emails +- VR https://lvra.gitlab.io/docs/distros/nixos/ # Tasks: +## Documentation +- [ ] project layout +- [ ] users file structure +- [ ] reverse proxy design + - public service compatibility + - vpn based services compatibility +- [ ] the choice of impermanence +- [ ] storage module design + - base impermanence compatibility and structure reason + - what does local vs persist mean in pool names (do we need a second layer? ephemeral, local, and persist? local exist only on this machine and is not backed up, persist is backed up to other machines (I think we need to redo the sops and torrent/media folders?)) + - plans to possibly support btrfs in the future + - plans for home manager datasets + - plans for auto systemd service datasets +- [ ] plans to migrate to some kind of acl structure for user management +- [ ] plans to migrate from flakes to npins + ## Chores: - [ ] test out crab hole service -- [ ] learn how to use actual ## Tech Debt - [ ] monitor configuration in `~/.config/monitors.xml` should be sym linked to `/run/gdm/.config/monitors.xml` (https://www.reddit.com/r/NixOS/comments/u09cz9/home_manager_create_my_own_symlinks_automatically/) - [ ] migrate away from flakes and move to npins -- [ ] rework the reverse_proxy.nix file so that it is a normally named service. Then also change it so that we can hook into it with both a base domain and a subdomain to make migrating to vpn accessible services easier +- [ ] `host.users` should be redone so that we just extend the base `users.users` object. Right now we cant quite do this because we have weird circular dependencies with disko/impermanence (not sure which one) and home manger enabling/disabling users per devices ## Broken things - [ ] figure out steam vr things? @@ -66,18 +83,27 @@ nix multi user, multi system, configuration with `sops` secret management, `home - [ ] rotate sops encryption keys periodically (and somehow sync between devices?) - [ ] Secure Boot - https://github.com/nix-community/lanzaboote - [ ] auto turn off on power loss - nut +- [ ] every service needs to have its own data pool +- [ ] secondary server with data sync. Maybe a Pi with a usb hdd enclosure and use rtcwake to only turn on once a week to sync data over tailscale with connection initiated from pi's side. We could probably put this at LZ. Hoping for it to draw only like $1 of power a month. Initial sync should probably be done here before we move it over because that will take a while. Data should be encrypted so that devices doesn't have access to it. Project will prob cost like $1800 ## Data Access - [ ] nfs export should be backed by the same values for server and client - [ ] samba mounts - [ ] offline access for nfs mounts (overlay with rsync might be a good option here? https://www.spinics.net/lists/linux-unionfs/msg07105.html note about nfs4 and overlay fs) - [ ] figure out why syncthing and jellyfins permissions don't propagate downwards -- [ ] make radarr, sonarr, and bazarr accessible over vpn -- [ ] move searx, home-assistant, actual, jellyfin, paperless, and immich to only be accessible via vpn +- [ ] make radarr, sonarr, and bazarr accessible over vpn with fully qualified names via reverse proxy +- [ ] move searx, home-assistant, actual, vikunja, jellyfin, paperless, and immich to only be accessible via vpn +- [ ] FreeIPA/SSSD/LDAP/Kerberos to manage uid and gid's ## Services +- [ ] ntfy service for unified push +- [ ] signal socket server - [ ] vikunja service for project management +- [ ] Penpot services (need to make this custom) +- [ ] minecraft server with old world file +- [ ] storj server - [ ] Create Tor guard/relay server +- [ ] screeps server - [ ] mastodon instance ## DevOps @@ -98,4 +124,7 @@ nix multi user, multi system, configuration with `sops` secret management, `home - [ ] postgres db load - [ ] nginx queries - [ ] ntfy.sh for push notifications -- [ ] kuma for uptime visualization \ No newline at end of file +- [ ] kuma for uptime visualization + +## Packages +- [ ] Custom private fork of MultiMC \ No newline at end of file diff --git a/configurations/home-manager/eve/packages.nix b/configurations/home-manager/eve/packages.nix index 73195c4..6b3c2e2 100644 --- a/configurations/home-manager/eve/packages.nix +++ b/configurations/home-manager/eve/packages.nix @@ -19,6 +19,7 @@ in { with pkgs; [ gnomeExtensions.dash-to-panel claude-code + friture ] ); @@ -32,9 +33,11 @@ in { (lib.mkIf (config.user.isDesktopUser || config.user.isTerminalUser) { git = { enable = true; - userName = "Eve"; - userEmail = "evesnrobins@gmail.com"; - extraConfig.init.defaultBranch = "main"; + settings = { + user.name = "Eve"; + user.email = "evesnrobins@gmail.com"; + init.defaultBranch = "main"; + }; }; openssh = { @@ -70,6 +73,7 @@ in { tor-browser.enable = true; olympus.enable = true; libreoffice.enable = true; + noita-entangled-worlds.enable = true; claude-code.enable = osConfig.host.ai.enable; diff --git a/configurations/home-manager/git/default.nix b/configurations/home-manager/git/default.nix index 2276e7a..1ea29cc 100644 --- a/configurations/home-manager/git/default.nix +++ b/configurations/home-manager/git/default.nix @@ -1,4 +1,6 @@ {osConfig, ...}: { + impermanence.fallbackPersistence.enable = false; + home = { username = osConfig.users.users.git.name; homeDirectory = osConfig.users.users.git.home; diff --git a/configurations/home-manager/leyla/default.nix b/configurations/home-manager/leyla/default.nix index eba7f7b..8a37754 100644 --- a/configurations/home-manager/leyla/default.nix +++ b/configurations/home-manager/leyla/default.nix @@ -12,6 +12,8 @@ ]; config = { + impermanence.enable = osConfig.host.impermanence.enable; + # Home Manager needs a bit of information about you and the paths it should # manage. home = { diff --git a/configurations/home-manager/leyla/packages/default.nix b/configurations/home-manager/leyla/packages/default.nix index 5bccad3..bc41350 100644 --- a/configurations/home-manager/leyla/packages/default.nix +++ b/configurations/home-manager/leyla/packages/default.nix @@ -9,7 +9,7 @@ in { imports = [ ./vscode - ./firefox.nix + ./firefox ./direnv.nix ./openssh.nix ./git.nix @@ -68,10 +68,9 @@ in { qflipper.enable = true; openvpn.enable = true; noisetorch.enable = true; + noita-entangled-worlds.enable = true; tor-browser.enable = true; gdx-liftoff.enable = true; - # polycule package is now working with Flutter 3.29 - polycule.enable = true; }) ]; } diff --git a/configurations/home-manager/leyla/packages/firefox.nix b/configurations/home-manager/leyla/packages/firefox.nix deleted file mode 100644 index d166eb4..0000000 --- a/configurations/home-manager/leyla/packages/firefox.nix +++ /dev/null @@ -1,344 +0,0 @@ -{ - lib, - pkgs, - inputs, - ... -}: { - config = { - programs.firefox = { - profiles.leyla = { - settings = { - "browser.search.defaultenginename" = "Searx"; - "browser.search.order.1" = "Searx"; - }; - - search = { - force = true; - default = "Searx"; - engines = { - "Nix Packages" = { - urls = [ - { - template = "https://search.nixos.org/packages"; - params = [ - { - name = "type"; - value = "packages"; - } - { - name = "query"; - value = "{searchTerms}"; - } - ]; - } - ]; - icon = "''${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; - definedAliases = ["@np"]; - }; - "NixOS Wiki" = { - urls = [{template = "https://nixos.wiki/index.php?search={searchTerms}";}]; - icon = "https://nixos.wiki/favicon.png"; - updateInterval = 24 * 60 * 60 * 1000; # every day - definedAliases = ["@nw"]; - }; - "Searx" = { - urls = [{template = "https://search.jan-leila.com/?q={searchTerms}";}]; - icon = "https://nixos.wiki/favicon.png"; - updateInterval = 24 * 60 * 60 * 1000; # every day - definedAliases = ["@searx"]; - }; - }; - }; - - extensions.packages = with inputs.firefox-addons.packages.${pkgs.system}; [ - bitwarden - terms-of-service-didnt-read - multi-account-containers - shinigami-eyes - - ublock-origin - sponsorblock - dearrow - df-youtube - return-youtube-dislikes - - privacy-badger - decentraleyes - clearurls - localcdn - - snowflake - - deutsch-de-language-pack - dictionary-german - - tab-session-manager - - # ( - # buildFirefoxXpiAddon rec { - # pname = "italiano-it-language-pack"; - # version = "132.0.20241110.231641"; - # addonId = "langpack-it@firefox.mozilla.org"; - # url = "https://addons.mozilla.org/firefox/downloads/file/4392453/italiano_it_language_pack-${version}.xpi"; - # sha256 = ""; - # meta = with lib; - # { - # description = "Firefox Language Pack for Italiano (it) – Italian"; - # license = licenses.mpl20; - # mozPermissions = []; - # platforms = platforms.all; - # }; - # } - # ) - # ( - # buildFirefoxXpiAddon rec { - # pname = "dizionario-italiano"; - # version = "5.1"; - # addonId = "it-IT@dictionaries.addons.mozilla.org"; - # url = "https://addons.mozilla.org/firefox/downloads/file/1163874/dizionario_italiano-${version}.xpi"; - # sha256 = ""; - # meta = with lib; - # { - # description = "Add support for Italian to spellchecking"; - # license = licenses.gpl3; - # mozPermissions = []; - # platforms = platforms.all; - # }; - # } - # ) - ]; - - settings = { - # Disable irritating first-run stuff - "browser.disableResetPrompt" = true; - "browser.download.panel.shown" = true; - "browser.feeds.showFirstRunUI" = false; - "browser.messaging-system.whatsNewPanel.enabled" = false; - "browser.rights.3.shown" = true; - "browser.shell.checkDefaultBrowser" = false; - "browser.shell.defaultBrowserCheckCount" = 1; - "browser.startup.homepage_override.mstone" = "ignore"; - "browser.uitour.enabled" = false; - "startup.homepage_override_url" = ""; - "trailhead.firstrun.didSeeAboutWelcome" = true; - "browser.bookmarks.restore_default_bookmarks" = false; - "browser.bookmarks.addedImportButton" = true; - "browser.newtabpage.activity-stream.feeds.section.topstories" = false; - - # Usage Experience - "browser.startup.homepage" = "about:home"; - "browser.download.useDownloadDir" = false; - "browser.uiCustomization.state" = builtins.toJSON { - "currentVersion" = 20; - "newElementCount" = 6; - "dirtyAreaCache" = [ - "nav-bar" - "PersonalToolbar" - "toolbar-menubar" - "TabsToolbar" - "unified-extensions-area" - "vertical-tabs" - ]; - "placements" = { - "widget-overflow-fixed-list" = []; - "unified-extensions-area" = [ - # bitwarden - "_446900e4-71c2-419f-a6a7-df9c091e268b_-browser-action" - "ublock0_raymondhill_net-browser-action" - "sponsorblocker_ajay_app-browser-action" - "dearrow_ajay_app-browser-action" - "jid1-mnnxcxisbpnsxq_jetpack-browser-action" - "_testpilot-containers-browser-action" - "addon_simplelogin-browser-action" - "_74145f27-f039-47ce-a470-a662b129930a_-browser-action" - "jid1-bofifl9vbdl2zq_jetpack-browser-action" - "dfyoutube_example_com-browser-action" - "_b86e4813-687a-43e6-ab65-0bde4ab75758_-browser-action" - "_762f9885-5a13-4abd-9c77-433dcd38b8fd_-browser-action" - "_b11bea1f-a888-4332-8d8a-cec2be7d24b9_-browse-action" - "jid0-3guet1r69sqnsrca5p8kx9ezc3u_jetpack-browser-action" - ]; - "nav-bar" = [ - "back-button" - "forward-button" - "stop-reload-button" - "urlbar-container" - "downloads-button" - "unified-extensions-button" - "reset-pbm-toolbar-button" - ]; - "toolbar-menubar" = [ - "menubar-items" - ]; - "TabsToolbar" = [ - "firefox-view-button" - "tabbrowser-tabs" - "new-tab-button" - "alltabs-button" - ]; - "vertical-tabs" = []; - "PersonalToolbar" = [ - "import-button" - "personal-bookmarks" - ]; - }; - "seen" = [ - "save-to-pocket-button" - "developer-button" - "privacy_privacy_com-browser-action" - "sponsorblocker_ajay_app-browser-action" - "ublock0_raymondhill_net-browser-action" - "addon_simplelogin-browser-action" - "dearrow_ajay_app-browser-action" - "_446900e4-71c2-419f-a6a7-df9c091e268b_-browser-action" - "_74145f27-f039-47ce-a470-a662b129930a_-browser-action" - "jid1-bofifl9vbdl2zq_jetpack-browser-action" - "dfyoutube_example_com-browser-action" - "_testpilot-containers-browser-action" - "_b86e4813-687a-43e6-ab65-0bde4ab75758_-browser-action" - "jid1-mnnxcxisbpnsxq_jetpack-browser-action" - "_762f9885-5a13-4abd-9c77-433dcd38b8fd_-browser-action" - "_b11bea1f-a888-4332-8d8a-cec2be7d24b9_-browser-action" - "jid0-3guet1r69sqnsrca5p8kx9ezc3u_jetpack-browser-action" - ]; - }; - "browser.newtabpage.activity-stream.feeds.topsites" = false; - "browser.newtabpage.activity-stream.showSponsoredTopSites" = false; - "browser.newtabpage.activity-stream.improvesearch.topSiteSearchShortcuts" = false; - "browser.newtabpage.blocked" = lib.genAttrs [ - # Facebook - "4gPpjkxgZzXPVtuEoAL9Ig==" - # Reddit - "gLv0ja2RYVgxKdp0I5qwvA==" - # Amazon - "K00ILysCaEq8+bEqV/3nuw==" - # Twitter - "T9nJot5PurhJSy8n038xGA==" - ] (_: 1); - "identity.fxaccounts.enabled" = false; - - # Security - "privacy.trackingprotection.enabled" = true; - "dom.security.https_only_mode" = true; - - "extensions.formautofill.addresses.enabled" = false; - "extensions.formautofill.creditCards.enabled" = false; - "signon.rememberSignons" = false; - "privacy.sanitize.sanitizeOnShutdown" = true; - "privacy.clearOnShutdown_v2.cache" = true; - "privacy.clearOnShutdown_v2.cookiesAndStorage" = true; - "privacy.clearOnShutdown_v2.historyFormDataAndDownloads" = true; - "urlclassifier.trackingSkipURLs" = ""; - "urlclassifier.features.socialtracking.skipURLs" = ""; - "dom.security.https_only_mode_pbm" = true; - "dom.security.https_only_mode_error_page_user_suggestions" = true; - - # Disable telemetry - "app.shield.optoutstudies.enabled" = false; - "browser.discovery.enabled" = false; - "browser.newtabpage.activity-stream.feeds.telemetry" = false; - "browser.newtabpage.activity-stream.telemetry" = false; - "browser.ping-centre.telemetry" = false; - "datareporting.healthreport.service.enabled" = false; - "datareporting.healthreport.uploadEnabled" = false; - "datareporting.policy.dataSubmissionEnabled" = false; - "datareporting.sessions.current.clean" = true; - "devtools.onboarding.telemetry.logged" = false; - "toolkit.telemetry.archive.enabled" = false; - "toolkit.telemetry.bhrPing.enabled" = false; - "toolkit.telemetry.enabled" = false; - "toolkit.telemetry.firstShutdownPing.enabled" = false; - "toolkit.telemetry.hybridContent.enabled" = false; - "toolkit.telemetry.newProfilePing.enabled" = false; - "toolkit.telemetry.prompted" = 2; - "toolkit.telemetry.rejected" = true; - "toolkit.telemetry.reportingpolicy.firstRun" = false; - "toolkit.telemetry.server" = ""; - "toolkit.telemetry.shutdownPingSender.enabled" = false; - "toolkit.telemetry.unified" = false; - "toolkit.telemetry.unifiedIsOptIn" = false; - "toolkit.telemetry.updatePing.enabled" = false; - }; - - bookmarks = { - force = true; - settings = [ - { - name = "Media"; - url = "https://media.jan-leila.com/"; - keyword = ""; - tags = [""]; - } - { - name = "Photos"; - url = "https://photos.jan-leila.com"; - keyword = ""; - tags = [""]; - } - { - name = "Git"; - url = "https://git.jan-leila.com/"; - keyword = ""; - tags = [""]; - } - { - name = "Home Automation"; - url = "https://home.jan-leila.com/"; - keyword = ""; - tags = [""]; - } - { - name = "Mail"; - url = "https://mail.protonmail.com"; - keyword = ""; - tags = [""]; - } - { - name = "Open Street Map"; - url = "https://www.openstreetmap.org/"; - keyword = ""; - tags = [""]; - } - { - name = "Password Manager"; - url = "https://vault.bitwarden.com/"; - keyword = ""; - tags = [""]; - } - { - name = "Mastodon"; - url = "https://mspsocial.net"; - keyword = ""; - tags = [""]; - } - { - name = "Linked In"; - url = "https://www.linkedin.com/"; - keyword = ""; - tags = [""]; - } - { - name = "Job Search"; - url = "https://www.jobsinnetwork.com/?state=cleaned_history&language%5B%5D=en&query=react&locations.countryCode%5B%5D=IT&locations.countryCode%5B%5D=DE&locations.countryCode%5B%5D=NL&experience%5B%5D=medior&experience%5B%5D=junior&page=1"; - keyword = ""; - tags = [""]; - } - { - name = "React Docs"; - url = "https://react.dev/"; - keyword = ""; - tags = [""]; - } - # Template - # { - # name = ""; - # url = ""; - # keyword = ""; - # tags = [""]; - # } - ]; - }; - }; - }; - }; -} diff --git a/configurations/home-manager/leyla/packages/firefox/bookmarks.nix b/configurations/home-manager/leyla/packages/firefox/bookmarks.nix new file mode 100644 index 0000000..4210d1e --- /dev/null +++ b/configurations/home-manager/leyla/packages/firefox/bookmarks.nix @@ -0,0 +1,155 @@ +{...}: { + programs.firefox = { + profiles.leyla = { + bookmarks = { + force = true; + settings = [ + # Personal Services + { + name = "Media"; + url = "https://media.jan-leila.com/"; + keyword = ""; + tags = [""]; + } + { + name = "Photos"; + url = "https://photos.jan-leila.com"; + keyword = ""; + tags = [""]; + } + { + name = "Git"; + url = "https://git.jan-leila.com/"; + keyword = ""; + tags = [""]; + } + { + name = "Home Automation"; + url = "https://home.jan-leila.com/"; + keyword = ""; + tags = [""]; + } + { + name = "Search"; + url = "https://search.jan-leila.com/"; + keyword = ""; + tags = [""]; + } + { + name = "Budget"; + url = "https://budget.jan-leila.com/"; + keyword = ""; + tags = [""]; + } + { + name = "Documents"; + url = "https://documents.jan-leila.com/"; + keyword = ""; + tags = [""]; + } + + # Defiant Server Services + { + name = "QBittorrent"; + url = "http://defiant:8084"; + keyword = ""; + tags = ["defiant"]; + } + { + name = "Sonarr"; + url = "http://defiant:8989"; + keyword = ""; + tags = ["defiant"]; + } + { + name = "Radarr"; + url = "http://defiant:7878"; + keyword = ""; + tags = ["defiant"]; + } + { + name = "Bazarr"; + url = "http://defiant:6767"; + keyword = ""; + tags = ["defiant"]; + } + { + name = "Lidarr"; + url = "http://defiant:8686"; + keyword = ""; + tags = ["defiant"]; + } + { + name = "Jackett"; + url = "http://defiant:9117"; + keyword = ""; + tags = ["defiant"]; + } + { + name = "Crab-hole DNS"; + url = "http://defiant:8085"; + keyword = ""; + tags = ["defiant"]; + } + + # External Services + { + name = "Mail"; + url = "https://mail.protonmail.com"; + keyword = ""; + tags = [""]; + } + { + name = "Open Street Map"; + url = "https://www.openstreetmap.org/"; + keyword = ""; + tags = [""]; + } + { + name = "Password Manager"; + url = "https://vault.bitwarden.com/"; + keyword = ""; + tags = [""]; + } + { + name = "Mastodon"; + url = "https://mspsocial.net"; + keyword = ""; + tags = [""]; + } + { + name = "Linked In"; + url = "https://www.linkedin.com/"; + keyword = ""; + tags = [""]; + } + { + name = "Job Search"; + url = "https://www.jobsinnetwork.com/?state=cleaned_history&language%5B%5D=en&query=react&locations.countryCode%5B%5D=IT&locations.countryCode%5B%5D=DE&locations.countryCode%5B%5D=NL&experience%5B%5D=medior&experience%5B%5D=junior&page=1"; + keyword = ""; + tags = [""]; + } + { + name = "React Docs"; + url = "https://react.dev/"; + keyword = ""; + tags = [""]; + } + { + name = "Cyberia Matrix"; + url = "https://chat.cyberia.club"; + keyword = ""; + tags = [""]; + } + # Template + # { + # name = ""; + # url = ""; + # keyword = ""; + # tags = [""]; + # } + ]; + }; + }; + }; +} diff --git a/configurations/home-manager/leyla/packages/firefox/default.nix b/configurations/home-manager/leyla/packages/firefox/default.nix new file mode 100644 index 0000000..4246c68 --- /dev/null +++ b/configurations/home-manager/leyla/packages/firefox/default.nix @@ -0,0 +1,18 @@ +{ + lib, + pkgs, + inputs, + ... +}: { + imports = [ + ./firefox.nix + ./bookmarks.nix + ./harden.nix + ]; + + config = { + programs.firefox = { + enable = true; + }; + }; +} diff --git a/configurations/home-manager/leyla/packages/firefox/firefox.nix b/configurations/home-manager/leyla/packages/firefox/firefox.nix new file mode 100644 index 0000000..ef6d202 --- /dev/null +++ b/configurations/home-manager/leyla/packages/firefox/firefox.nix @@ -0,0 +1,191 @@ +{ + lib, + pkgs, + inputs, + ... +}: { + programs.firefox = { + profiles.leyla = { + settings = { + "browser.search.defaultenginename" = "Searx"; + "browser.search.order.1" = "Searx"; + }; + + search = { + force = true; + default = "Searx"; + engines = { + "Nix Packages" = { + urls = [ + { + template = "https://search.nixos.org/packages"; + params = [ + { + name = "type"; + value = "packages"; + } + { + name = "query"; + value = "{searchTerms}"; + } + ]; + } + ]; + icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; + definedAliases = ["@np"]; + }; + "NixOS Wiki" = { + urls = [{template = "https://nixos.wiki/index.php?search={searchTerms}";}]; + icon = "https://nixos.wiki/favicon.png"; + updateInterval = 24 * 60 * 60 * 1000; # every day + definedAliases = ["@nw"]; + }; + "Searx" = { + urls = [{template = "https://search.jan-leila.com/?q={searchTerms}";}]; + icon = "https://nixos.wiki/favicon.png"; + updateInterval = 24 * 60 * 60 * 1000; # every day + definedAliases = ["@searx"]; + }; + }; + }; + + extensions.packages = with inputs.firefox-addons.packages.${pkgs.stdenv.hostPlatform.system}; [ + bitwarden + terms-of-service-didnt-read + multi-account-containers + shinigami-eyes + + ublock-origin + sponsorblock + dearrow + df-youtube + return-youtube-dislikes + + privacy-badger + decentraleyes + clearurls + localcdn + + snowflake + + pkgs.firefox-extensions.deutsch-de-language-pack + dictionary-german + + tab-session-manager + + pkgs.firefox-extensions.italiano-it-language-pack + pkgs.firefox-extensions.dizionario-italiano + ]; + + settings = { + # Disable irritating first-run stuff + "browser.disableResetPrompt" = true; + "browser.download.panel.shown" = true; + "browser.feeds.showFirstRunUI" = false; + "browser.messaging-system.whatsNewPanel.enabled" = false; + "browser.rights.3.shown" = true; + "browser.shell.checkDefaultBrowser" = false; + "browser.shell.defaultBrowserCheckCount" = 1; + "browser.startup.homepage_override.mstone" = "ignore"; + "browser.uitour.enabled" = false; + "startup.homepage_override_url" = ""; + "trailhead.firstrun.didSeeAboutWelcome" = true; + "browser.bookmarks.restore_default_bookmarks" = false; + "browser.bookmarks.addedImportButton" = true; + "browser.newtabpage.activity-stream.feeds.section.topstories" = false; + + # Usage Experience + "browser.startup.homepage" = "about:home"; + "browser.download.useDownloadDir" = false; + "browser.uiCustomization.state" = builtins.toJSON { + "currentVersion" = 20; + "newElementCount" = 6; + "dirtyAreaCache" = [ + "nav-bar" + "PersonalToolbar" + "toolbar-menubar" + "TabsToolbar" + "unified-extensions-area" + "vertical-tabs" + ]; + "placements" = { + "widget-overflow-fixed-list" = []; + "unified-extensions-area" = [ + # bitwarden + "_446900e4-71c2-419f-a6a7-df9c091e268b_-browser-action" + "ublock0_raymondhill_net-browser-action" + "sponsorblocker_ajay_app-browser-action" + "dearrow_ajay_app-browser-action" + "jid1-mnnxcxisbpnsxq_jetpack-browser-action" + "_testpilot-containers-browser-action" + "addon_simplelogin-browser-action" + "_74145f27-f039-47ce-a470-a662b129930a_-browser-action" + "jid1-bofifl9vbdl2zq_jetpack-browser-action" + "dfyoutube_example_com-browser-action" + "_b86e4813-687a-43e6-ab65-0bde4ab75758_-browser-action" + "_762f9885-5a13-4abd-9c77-433dcd38b8fd_-browser-action" + "_b11bea1f-a888-4332-8d8a-cec2be7d24b9_-browse-action" + "jid0-3guet1r69sqnsrca5p8kx9ezc3u_jetpack-browser-action" + ]; + "nav-bar" = [ + "back-button" + "forward-button" + "stop-reload-button" + "urlbar-container" + "downloads-button" + "unified-extensions-button" + "reset-pbm-toolbar-button" + ]; + "toolbar-menubar" = [ + "menubar-items" + ]; + "TabsToolbar" = [ + "firefox-view-button" + "tabbrowser-tabs" + "new-tab-button" + "alltabs-button" + ]; + "vertical-tabs" = []; + "PersonalToolbar" = [ + "import-button" + "personal-bookmarks" + ]; + }; + "seen" = [ + "save-to-pocket-button" + "developer-button" + "privacy_privacy_com-browser-action" + "sponsorblocker_ajay_app-browser-action" + "ublock0_raymondhill_net-browser-action" + "addon_simplelogin-browser-action" + "dearrow_ajay_app-browser-action" + "_446900e4-71c2-419f-a6a7-df9c091e268b_-browser-action" + "_74145f27-f039-47ce-a470-a662b129930a_-browser-action" + "jid1-bofifl9vbdl2zq_jetpack-browser-action" + "dfyoutube_example_com-browser-action" + "_testpilot-containers-browser-action" + "_b86e4813-687a-43e6-ab65-0bde4ab75758_-browser-action" + "jid1-mnnxcxisbpnsxq_jetpack-browser-action" + "_762f9885-5a13-4abd-9c77-433dcd38b8fd_-browser-action" + "_b11bea1f-a888-4332-8d8a-cec2be7d24b9_-browser-action" + "jid0-3guet1r69sqnsrca5p8kx9ezc3u_jetpack-browser-action" + ]; + }; + "browser.newtabpage.activity-stream.feeds.topsites" = false; + "browser.newtabpage.activity-stream.showSponsoredTopSites" = false; + "browser.newtabpage.activity-stream.improvesearch.topSiteSearchShortcuts" = false; + "browser.newtabpage.blocked" = lib.genAttrs [ + # Facebook + "4gPpjkxgZzXPVtuEoAL9Ig==" + # Reddit + "gLv0ja2RYVgxKdp0I5qwvA==" + # Amazon + "K00ILysCaEq8+bEqV/3nuw==" + # Twitter + "T9nJot5PurhJSy8n038xGA==" + ] (_: 1); + "identity.fxaccounts.enabled" = false; + }; + }; + }; +} diff --git a/configurations/home-manager/leyla/packages/firefox/harden.nix b/configurations/home-manager/leyla/packages/firefox/harden.nix new file mode 100644 index 0000000..66310c2 --- /dev/null +++ b/configurations/home-manager/leyla/packages/firefox/harden.nix @@ -0,0 +1,50 @@ +{...}: { + programs.firefox = { + profiles.leyla = { + settings = { + # Security + "privacy.trackingprotection.enabled" = true; + "dom.security.https_only_mode" = true; + "dom.security.https_only_mode_pbm" = true; + "dom.security.https_only_mode_error_page_user_suggestions" = true; + + # Privacy & Data Protection + "extensions.formautofill.addresses.enabled" = false; + "extensions.formautofill.creditCards.enabled" = false; + "signon.rememberSignons" = false; + "privacy.sanitize.sanitizeOnShutdown" = true; + "privacy.clearOnShutdown_v2.cache" = true; + "privacy.clearOnShutdown_v2.cookiesAndStorage" = true; + "privacy.clearOnShutdown_v2.historyFormDataAndDownloads" = true; + "urlclassifier.trackingSkipURLs" = ""; + "urlclassifier.features.socialtracking.skipURLs" = ""; + + # Disable telemetry and data collection + "app.shield.optoutstudies.enabled" = false; + "browser.discovery.enabled" = false; + "browser.newtabpage.activity-stream.feeds.telemetry" = false; + "browser.newtabpage.activity-stream.telemetry" = false; + "browser.ping-centre.telemetry" = false; + "datareporting.healthreport.service.enabled" = false; + "datareporting.healthreport.uploadEnabled" = false; + "datareporting.policy.dataSubmissionEnabled" = false; + "datareporting.sessions.current.clean" = true; + "devtools.onboarding.telemetry.logged" = false; + "toolkit.telemetry.archive.enabled" = false; + "toolkit.telemetry.bhrPing.enabled" = false; + "toolkit.telemetry.enabled" = false; + "toolkit.telemetry.firstShutdownPing.enabled" = false; + "toolkit.telemetry.hybridContent.enabled" = false; + "toolkit.telemetry.newProfilePing.enabled" = false; + "toolkit.telemetry.prompted" = 2; + "toolkit.telemetry.rejected" = true; + "toolkit.telemetry.reportingpolicy.firstRun" = false; + "toolkit.telemetry.server" = ""; + "toolkit.telemetry.shutdownPingSender.enabled" = false; + "toolkit.telemetry.unified" = false; + "toolkit.telemetry.unifiedIsOptIn" = false; + "toolkit.telemetry.updatePing.enabled" = false; + }; + }; + }; +} diff --git a/configurations/home-manager/leyla/packages/git.nix b/configurations/home-manager/leyla/packages/git.nix index 568cd7a..499e37b 100644 --- a/configurations/home-manager/leyla/packages/git.nix +++ b/configurations/home-manager/leyla/packages/git.nix @@ -2,9 +2,11 @@ config = { programs = { git = { - userName = "Leyla Becker"; - userEmail = "git@jan-leila.com"; - extraConfig.init.defaultBranch = "main"; + settings = { + user.name = "Leyla Becker"; + user.email = "git@jan-leila.com"; + init.defaultBranch = "main"; + }; }; }; }; diff --git a/configurations/home-manager/leyla/packages/vscode/default.nix b/configurations/home-manager/leyla/packages/vscode/default.nix index fd72006..36168b2 100644 --- a/configurations/home-manager/leyla/packages/vscode/default.nix +++ b/configurations/home-manager/leyla/packages/vscode/default.nix @@ -69,6 +69,9 @@ in { # go development go.enable = true; + # rust development + rustAnalyzer.enable = true; + # claude development claudeDev = lib.mkIf ai-tooling-enabled { enable = true; diff --git a/configurations/nixos/defiant/configuration.nix b/configurations/nixos/defiant/configuration.nix index c2b8fc5..e2f9401 100644 --- a/configurations/nixos/defiant/configuration.nix +++ b/configurations/nixos/defiant/configuration.nix @@ -102,18 +102,6 @@ directories = ["leyla_documents" "eve_documents" "users_documents" "media"]; }; }; - reverse_proxy = { - enable = true; - enableACME = true; - hostname = "jan-leila.com"; - }; - postgres = { - extraUsers = { - leyla = { - isAdmin = true; - }; - }; - }; }; systemd.network = { @@ -225,6 +213,12 @@ }; services = { + # PostgreSQL database server + postgresql = { + enable = true; + adminUsers = ["leyla"]; + }; + # temp enable desktop environment for setup # Enable the X11 windowing system. xserver.enable = true; @@ -237,6 +231,16 @@ gnome.enable = true; }; + # Enable new reverse proxy system + reverseProxy = { + enable = true; + openFirewall = true; + acme = { + enable = true; + email = "jan-leila@protonmail.com"; + }; + }; + ollama = { enable = true; exposePort = true; @@ -294,35 +298,35 @@ jellyfin = { enable = true; - subdomain = "media"; - extraSubdomains = ["jellyfin"]; + domain = "media.jan-leila.com"; + extraDomains = ["jellyfin.jan-leila.com"]; }; immich = { enable = true; - subdomain = "photos"; + domain = "photos.jan-leila.com"; }; forgejo = { enable = true; - subdomain = "git"; + reverseProxy.domain = "git.jan-leila.com"; }; searx = { enable = true; - subdomain = "search"; + domain = "search.jan-leila.com"; }; actual = { - enable = false; - subdomain = "budget"; + enable = true; + domain = "budget.jan-leila.com"; }; home-assistant = { enable = true; - subdomain = "home"; + domain = "home.jan-leila.com"; openFirewall = true; - database = "postgres"; + postgres.enable = true; extensions = { sonos.enable = true; @@ -333,7 +337,7 @@ paperless = { enable = true; - subdomain = "documents"; + domain = "documents.jan-leila.com"; passwordFile = config.sops.secrets."services/paperless_password".path; }; @@ -348,12 +352,13 @@ openFirewall = true; show_doc = true; downstreams = { - loopback = { + host = { enable = true; openFirewall = true; }; }; upstreams.cloudFlare.enable = true; + blocklists.ad_malware.enable = true; }; qbittorrent = { diff --git a/flake.lock b/flake.lock index bb7e3a6..a3c552f 100644 --- a/flake.lock +++ b/flake.lock @@ -25,11 +25,11 @@ ] }, "locked": { - "lastModified": 1760701190, - "narHash": "sha256-y7UhnWlER8r776JsySqsbTUh2Txf7K30smfHlqdaIQw=", + "lastModified": 1763651264, + "narHash": "sha256-8vvwZbw0s7YvBMJeyPVpWke6lg6ROgtts5N2/SMCcv4=", "owner": "nix-community", "repo": "disko", - "rev": "3a9450b26e69dcb6f8de6e2b07b3fc1c288d85f5", + "rev": "e86a89079587497174ccab6d0d142a65811a4fd9", "type": "github" }, "original": { @@ -46,11 +46,11 @@ }, "locked": { "dir": "pkgs/firefox-addons", - "lastModified": 1760673822, - "narHash": "sha256-h+liPhhMw1yYvkDGLHzQJQShQs+yLjNgjfAyZX+sRrM=", + "lastModified": 1763697825, + "narHash": "sha256-AgCCcVPOi1tuzuW5/StlwqBjRWSX62oL97qWuxrq5UA=", "owner": "rycee", "repo": "nur-expressions", - "rev": "5cca27f1bb30a26140d0cf60ab34daa45b4fa11f", + "rev": "cefce78793603231be226fa77e7ad58e0e4899b8", "type": "gitlab" }, "original": { @@ -62,11 +62,11 @@ }, "flake-compat": { "locked": { - "lastModified": 1747046372, - "narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=", + "lastModified": 1761588595, + "narHash": "sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4=", "owner": "edolstra", "repo": "flake-compat", - "rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885", + "rev": "f387cd2afec9419c8ee37694406ca490c3f34ee5", "type": "github" }, "original": { @@ -133,11 +133,11 @@ ] }, "locked": { - "lastModified": 1760662441, - "narHash": "sha256-mlDqR1Ntgs9uYYEAUR1IhamKBO0lxoNS4zGLzEZaY0A=", + "lastModified": 1763748372, + "narHash": "sha256-AUc78Qv3sWir0hvbmfXoZ7Jzq9VVL97l+sP9Jgms+JU=", "owner": "nix-community", "repo": "home-manager", - "rev": "722792af097dff5790f1a66d271a47759f477755", + "rev": "d10a9b16b2a3ee28433f3d1c603f4e9f1fecb8e1", "type": "github" }, "original": { @@ -164,11 +164,11 @@ "lix": { "flake": false, "locked": { - "lastModified": 1755787066, - "narHash": "sha256-X2UwkUEban08GRSPXRr+kz8fckHqebr3P77qSvjoeOw=", - "rev": "ac9721a92e8138d29707824dbedb484c76948493", + "lastModified": 1761937274, + "narHash": "sha256-KlELhsSq3XbemrGyQhmGurFu7m8wOEBw+8M04L7hn7A=", + "rev": "91867941fa73afea7869b7c71ede82e5ef8927da", "type": "tarball", - "url": "https://git.lix.systems/api/v1/repos/lix-project/lix/archive/ac9721a92e8138d29707824dbedb484c76948493.tar.gz?rev=ac9721a92e8138d29707824dbedb484c76948493" + "url": "https://git.lix.systems/api/v1/repos/lix-project/lix/archive/91867941fa73afea7869b7c71ede82e5ef8927da.tar.gz?rev=91867941fa73afea7869b7c71ede82e5ef8927da" }, "original": { "type": "tarball", @@ -185,11 +185,11 @@ ] }, "locked": { - "lastModified": 1759851320, - "narHash": "sha256-n5dRAIC3/78drQtFxmQRrBLd6TKfotUnX7GWu0mAcSg=", + "lastModified": 1763435414, + "narHash": "sha256-i2467FddWfd19q5Qoj+1/BAeg6LZmM5m4mYGRSQn/as=", "ref": "refs/heads/main", - "rev": "7c31a18259b8358ac196cf803a26967c0fa1d3e4", - "revCount": 163, + "rev": "192c92b603731fbc1bade6c1b18c8d8a0086f703", + "revCount": 169, "type": "git", "url": "https://git.lix.systems/lix-project/nixos-module.git" }, @@ -207,11 +207,11 @@ ] }, "locked": { - "lastModified": 1759342933, - "narHash": "sha256-mdlUFcrOfvT0Pm+Hko/6aR3xf1ao5JA2iem4KsEVjP4=", + "lastModified": 1760821194, + "narHash": "sha256-UCsJ8eDuHL14u2GFIYEY/drtZ6jht5zN/G/6QNlEy2g=", "owner": "utensils", "repo": "mcp-nixos", - "rev": "50b02bcba32b941d2ec48fedef68641702ca5b0f", + "rev": "0ae453f38d0f088c31d4678da3a12b183165986f", "type": "github" }, "original": { @@ -227,11 +227,11 @@ ] }, "locked": { - "lastModified": 1760721282, - "narHash": "sha256-aAHphQbU9t/b2RRy2Eb8oMv+I08isXv2KUGFAFn7nCo=", + "lastModified": 1763505477, + "narHash": "sha256-nJRd4LY2kT3OELfHqdgWjvToNZ4w+zKCMzS2R6z4sXE=", "owner": "LnL7", "repo": "nix-darwin", - "rev": "c3211fcd0c56c11ff110d346d4487b18f7365168", + "rev": "3bda9f6b14161becbd07b3c56411f1670e19b9b5", "type": "github" }, "original": { @@ -268,11 +268,11 @@ ] }, "locked": { - "lastModified": 1760720017, - "narHash": "sha256-ALb+L8zaP6IJ3BigQJ+ih7NqmaptzL/CbkNkLbhmsGE=", + "lastModified": 1763690163, + "narHash": "sha256-MMl9P8f17unCvlk2IAinnMq/P72f51UUHVRIYnojT7w=", "owner": "nix-community", "repo": "nix-vscode-extensions", - "rev": "b0897a5d1d5829eb67ca7168680873ee7a0d52b8", + "rev": "590349d9faeb398a037205c2927ffbaede980539", "type": "github" }, "original": { @@ -283,11 +283,11 @@ }, "nixos-hardware": { "locked": { - "lastModified": 1760106635, - "narHash": "sha256-2GoxVaKWTHBxRoeUYSjv0AfSOx4qw5CWSFz2b+VolKU=", + "lastModified": 1762847253, + "narHash": "sha256-BWWnUUT01lPwCWUvS0p6Px5UOBFeXJ8jR+ZdLX8IbrU=", "owner": "NixOS", "repo": "nixos-hardware", - "rev": "9ed85f8afebf2b7478f25db0a98d0e782c0ed903", + "rev": "899dc449bc6428b9ee6b3b8f771ca2b0ef945ab9", "type": "github" }, "original": { @@ -315,11 +315,11 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1760524057, - "narHash": "sha256-EVAqOteLBFmd7pKkb0+FIUyzTF61VKi7YmvP1tw4nEw=", + "lastModified": 1763421233, + "narHash": "sha256-Stk9ZYRkGrnnpyJ4eqt9eQtdFWRRIvMxpNRf4sIegnw=", "owner": "nixos", "repo": "nixpkgs", - "rev": "544961dfcce86422ba200ed9a0b00dd4b1486ec5", + "rev": "89c2b2330e733d6cdb5eae7b899326930c2c0648", "type": "github" }, "original": { @@ -329,6 +329,43 @@ "type": "github" } }, + "nixpkgs_3": { + "locked": { + "lastModified": 1759070547, + "narHash": "sha256-JVZl8NaVRYb0+381nl7LvPE+A774/dRpif01FKLrYFQ=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "647e5c14cbd5067f44ac86b74f014962df460840", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "noita-entangled-worlds": { + "inputs": { + "nixpkgs": "nixpkgs_3", + "rust-overlay": "rust-overlay", + "systems": "systems_3" + }, + "locked": { + "lastModified": 1764204484, + "narHash": "sha256-S45ghD/YjcKDy8Mz3DYklLMaA/z6f6mTbx0i7pAktYk=", + "owner": "IntQuant", + "repo": "noita_entangled_worlds", + "rev": "ab2c2162157140ab519fa19f6737c044e1ed0e3b", + "type": "github" + }, + "original": { + "owner": "IntQuant", + "ref": "master", + "repo": "noita_entangled_worlds", + "type": "github" + } + }, "root": { "inputs": { "disko": "disko", @@ -343,10 +380,32 @@ "nix-vscode-extensions": "nix-vscode-extensions", "nixos-hardware": "nixos-hardware", "nixpkgs": "nixpkgs_2", + "noita-entangled-worlds": "noita-entangled-worlds", "secrets": "secrets", "sops-nix": "sops-nix" } }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "noita-entangled-worlds", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1759199574, + "narHash": "sha256-w24RYly3VSVKp98rVfCI1nFYfQ0VoWmShtKPCbXgK6A=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "381776b12d0d125edd7c1930c2041a1471e586c0", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, "secrets": { "flake": false, "locked": { @@ -370,11 +429,11 @@ ] }, "locked": { - "lastModified": 1760393368, - "narHash": "sha256-8mN3kqyqa2PKY0wwZ2UmMEYMcxvNTwLaOrrDsw6Qi4E=", + "lastModified": 1763607916, + "narHash": "sha256-VefBA1JWRXM929mBAFohFUtQJLUnEwZ2vmYUNkFnSjE=", "owner": "Mic92", "repo": "sops-nix", - "rev": "ab8d56e85b8be14cff9d93735951e30c3e86a437", + "rev": "877bb495a6f8faf0d89fc10bd142c4b7ed2bcc0b", "type": "github" }, "original": { @@ -412,6 +471,22 @@ "repo": "default", "type": "github" } + }, + "systems_3": { + "flake": false, + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index ddf92ce..e935688 100644 --- a/flake.nix +++ b/flake.nix @@ -77,6 +77,12 @@ url = "github:utensils/mcp-nixos"; inputs.nixpkgs.follows = "nixpkgs"; }; + + # Noita Entangled Worlds package + # Not following our nixpkgs so it can use its own rust-overlay configuration + noita-entangled-worlds = { + url = "github:IntQuant/noita_entangled_worlds/master"; + }; }; outputs = { @@ -91,15 +97,9 @@ util = import ./util {inherit inputs;}; forEachPkgs = util.forEachPkgs; - mkNixosInstaller = util.mkNixosInstaller; mkNixosSystem = util.mkNixosSystem; mkDarwinSystem = util.mkDarwinSystem; mkHome = util.mkHome; - syncthingConfiguration = util.syncthingConfiguration; - - installerSystems = { - basic = mkNixosInstaller "basic" []; - }; nixosSystems = { horizon = mkNixosSystem "horizon"; @@ -170,14 +170,10 @@ }; }); - installerConfigurations = installerSystems; - nixosConfigurations = nixosSystems; darwinConfigurations = darwinSystems; homeConfigurations = homeConfigurations; - - syncthingConfiguration = syncthingConfiguration; }; } diff --git a/modules/common-modules/overlays/default.nix b/modules/common-modules/overlays/default.nix index 2c0f712..3def9e9 100644 --- a/modules/common-modules/overlays/default.nix +++ b/modules/common-modules/overlays/default.nix @@ -2,5 +2,9 @@ {inputs, ...}: { nixpkgs.overlays = [ inputs.nix-vscode-extensions.overlays.default + # Add noita_entangled_worlds from upstream flake to pkgs + (final: prev: { + noita_entangled_worlds = inputs.noita-entangled-worlds.packages.${prev.stdenv.hostPlatform.system}.noita-proxy; + }) ]; } diff --git a/modules/common-modules/pkgs/default.nix b/modules/common-modules/pkgs/default.nix index a2f61b1..2afc9f2 100644 --- a/modules/common-modules/pkgs/default.nix +++ b/modules/common-modules/pkgs/default.nix @@ -1,4 +1,8 @@ -{pkgs, ...}: { +{ + pkgs, + inputs, + ... +}: { imports = [ ./python ]; @@ -16,15 +20,17 @@ ./prostudiomasters.nix {}; }) - (final: prev: { - noita_entangled_worlds = pkgs.callPackage ./noita-entangled-worlds.nix {}; - }) (final: prev: { gdx-liftoff = pkgs.callPackage ./gdx-liftoff.nix {}; }) (final: prev: { codium-extensions = pkgs.callPackage ./codium-extensions {}; }) + (final: prev: { + firefox-extensions = pkgs.callPackage ./firefox-extensions { + inherit inputs; + }; + }) (final: prev: { mapillary-uploader = pkgs.callPackage ./mapillary-uploader.nix {}; }) @@ -38,8 +44,5 @@ # Override h3 C library to version 4.3.0 h3 = pkgs.callPackage ./h3-c-lib.nix {}; }) - (final: prev: { - polycule = pkgs.callPackage ./polycule {}; - }) ]; } diff --git a/modules/common-modules/pkgs/firefox-extensions/default.nix b/modules/common-modules/pkgs/firefox-extensions/default.nix new file mode 100644 index 0000000..922dfc7 --- /dev/null +++ b/modules/common-modules/pkgs/firefox-extensions/default.nix @@ -0,0 +1,17 @@ +{ + pkgs, + inputs, + ... +}: let + inherit (inputs.firefox-addons.lib.${pkgs.stdenv.hostPlatform.system}) buildFirefoxXpiAddon; +in { + italiano-it-language-pack = pkgs.callPackage ./italiano-it-language-pack.nix { + inherit buildFirefoxXpiAddon; + }; + dizionario-italiano = pkgs.callPackage ./dizionario-italiano.nix { + inherit buildFirefoxXpiAddon; + }; + deutsch-de-language-pack = pkgs.callPackage ./deutsch-de-language-pack.nix { + inherit buildFirefoxXpiAddon; + }; +} diff --git a/modules/common-modules/pkgs/firefox-extensions/deutsch-de-language-pack.nix b/modules/common-modules/pkgs/firefox-extensions/deutsch-de-language-pack.nix new file mode 100644 index 0000000..b769bfd --- /dev/null +++ b/modules/common-modules/pkgs/firefox-extensions/deutsch-de-language-pack.nix @@ -0,0 +1,18 @@ +{ + lib, + buildFirefoxXpiAddon, + ... +}: +buildFirefoxXpiAddon rec { + pname = "deutsch-de-language-pack"; + version = "145.0.20251106.194447"; + addonId = "langpack-de@firefox.mozilla.org"; + url = "https://addons.mozilla.org/firefox/downloads/file/4614311/deutsch_de_language_pack-${version}.xpi"; + sha256 = "aaaa95c29984fb3802a5e7edb6b7e5020c391d81f389b8a8133c163959ea4299"; + meta = with lib; { + description = "Firefox Language Pack for Deutsch (de) – German"; + license = licenses.mpl20; + mozPermissions = []; + platforms = platforms.all; + }; +} diff --git a/modules/common-modules/pkgs/firefox-extensions/dizionario-italiano.nix b/modules/common-modules/pkgs/firefox-extensions/dizionario-italiano.nix new file mode 100644 index 0000000..4bfca14 --- /dev/null +++ b/modules/common-modules/pkgs/firefox-extensions/dizionario-italiano.nix @@ -0,0 +1,18 @@ +{ + lib, + buildFirefoxXpiAddon, + ... +}: +buildFirefoxXpiAddon rec { + pname = "dizionario-italiano"; + version = "5.1"; + addonId = "it-IT@dictionaries.addons.mozilla.org"; + url = "https://addons.mozilla.org/firefox/downloads/file/3693497/dizionario_italiano-${version}.xpi"; + sha256 = "90b173ffdde34a77108152a5ff51879767b1dd84e0aa0dfb7b2bab94cd2e7f53"; + meta = with lib; { + description = "Add support for Italian to spellchecking"; + license = licenses.gpl3; + mozPermissions = []; + platforms = platforms.all; + }; +} diff --git a/modules/common-modules/pkgs/firefox-extensions/italiano-it-language-pack.nix b/modules/common-modules/pkgs/firefox-extensions/italiano-it-language-pack.nix new file mode 100644 index 0000000..35f4243 --- /dev/null +++ b/modules/common-modules/pkgs/firefox-extensions/italiano-it-language-pack.nix @@ -0,0 +1,18 @@ +{ + lib, + buildFirefoxXpiAddon, + ... +}: +buildFirefoxXpiAddon rec { + pname = "italiano-it-language-pack"; + version = "145.0.20251106.194447"; + addonId = "langpack-it@firefox.mozilla.org"; + url = "https://addons.mozilla.org/firefox/downloads/file/4614309/italiano_it_language_pack-${version}.xpi"; + sha256 = "1eb271cedbf326543e222ba1b9a1da62fceef9d3c523ac02a098df296f155038"; + meta = with lib; { + description = "Firefox Language Pack for Italiano (it) – Italian"; + license = licenses.mpl20; + mozPermissions = []; + platforms = platforms.all; + }; +} diff --git a/modules/common-modules/pkgs/mapillary-uploader.nix b/modules/common-modules/pkgs/mapillary-uploader.nix index 9ae2ea7..acff772 100644 --- a/modules/common-modules/pkgs/mapillary-uploader.nix +++ b/modules/common-modules/pkgs/mapillary-uploader.nix @@ -9,7 +9,7 @@ src = fetchurl { url = "http://tools.mapillary.com/uploader/download/linux/${version}"; name = "mapillary-uploader.AppImage"; - sha256 = "sha256-OY3SiMHUyjwPDrPWfa+mFg2BHZrz6GG/9/D5sCP2Da8="; + sha256 = "sha256-hpWdfeuhYylO+SFD3BsKI0s/xtObCDd5OcuJ6i/aEuI="; }; appimageContents = appimageTools.extractType2 { diff --git a/modules/common-modules/pkgs/noita-entangled-worlds.nix b/modules/common-modules/pkgs/noita-entangled-worlds.nix deleted file mode 100644 index 322ce41..0000000 --- a/modules/common-modules/pkgs/noita-entangled-worlds.nix +++ /dev/null @@ -1,46 +0,0 @@ -# not working yet -{ - pkgs, - rustPlatform, - fetchFromGitHub, - ... -}: let - version = "1.5.3"; - repo = fetchFromGitHub { - owner = "IntQuant"; - repo = "noita_entangled_worlds"; - rev = "v${version}"; - hash = "sha256-frrpD0aWTeDbZYtp15R+quUUAZf7OvHlbSLtGJJtAqk="; - }; -in - rustPlatform.buildRustPackage { - name = "noita-proxy-${version}"; - src = repo + "/noita-proxy"; - prePatch = '' - substituteInPlace Cargo.toml \ - --replace "path = \"../shared\"" "path = \"${repo + "/shared"}\"" - ''; - nativeBuildInputs = with pkgs; [ - pkg-config - python3 - cmake - ]; - buildInputs = with pkgs; [ - openssl - openssl.dev - libpulseaudio - libjack2 - alsa-lib - xorg.libxcb - xorg.libxcb.dev - libopus - ]; - propagatedBuildInputs = with pkgs; [ - steamworks-sdk-redist - ]; - runtimeDependencies = with pkgs; [ - steamworks-sdk-redist - ]; - doCheck = false; - cargoHash = "sha256-TzUS6d6PopgGf2i1yVaXaXdzNrvfSz+Gv67BAtxYmb4="; - } diff --git a/modules/common-modules/pkgs/polycule/default.nix b/modules/common-modules/pkgs/polycule/default.nix deleted file mode 100644 index b463cc5..0000000 --- a/modules/common-modules/pkgs/polycule/default.nix +++ /dev/null @@ -1,149 +0,0 @@ -{ - lib, - flutter332, - fetchFromGitLab, - pkg-config, - wrapGAppsHook, - gtk3, - glib, - glib-networking, - webkitgtk_4_1, - libsecret, - libnotify, - dbus, - sqlcipher, - openssl, - mpv, - alsa-lib, - libass, - ffmpeg-full, - libplacebo, - libunwind, - shaderc, - vulkan-headers, - vulkan-loader, - lcms2, - libdovi, - libdvdnav, - libdvdread, - mujs, - libbluray, - lua, - rubberband, - libuchardet, - zimg, - openal, - pipewire, - libpulseaudio, - libcaca, - libdrm, - libdisplay-info, - libgbm, - xorg, - nv-codec-headers-11, - libva, - libvdpau, -}: -flutter332.buildFlutterApplication rec { - pname = "polycule"; - version = "0.3.4"; - - src = fetchFromGitLab { - owner = "polycule_client"; - repo = "polycule"; - rev = "v${version}"; - hash = "sha256-RUu8DKuX2NUU5Ce5WLHtDaORkn7CSrgTj3KhM/z+yHc="; - }; - - pubspecLock = lib.importJSON ./polycule-pubspec.lock.json; - - gitHashes = { - matrix = "sha256-w/QB5nYJ9Lh77TcYKEN/DnNQjWfp+9NX0dwQ9GOzWE8="; - media_kit = "sha256-1sVX+aHFLFJBtrNZrR6tWkb80vFELW2N9EejyQKlBPg="; - media_kit_libs_android_video = "sha256-N6QoktM8u9NYF8MAXLsxM9RlV8nICM4NbnmABHTRkZg="; - }; - - nativeBuildInputs = [ - pkg-config - wrapGAppsHook - ]; - - buildInputs = [ - gtk3 - glib - glib-networking - webkitgtk_4_1 - libsecret - libnotify - dbus - sqlcipher - openssl - mpv - alsa-lib - libass - ffmpeg-full - libplacebo - libunwind - shaderc - vulkan-headers - vulkan-loader - lcms2 - libdovi - libdvdnav - libdvdread - mujs - libbluray - lua - rubberband - libuchardet - zimg - openal - pipewire - libpulseaudio - libcaca - libdrm - libdisplay-info - libgbm - xorg.libXScrnSaver - xorg.libXpresent - nv-codec-headers-11 - libva - libvdpau - ]; - - flutterBuildFlags = [ - "--release" - "--target" - "lib/main.dart" - "--dart-define=POLYCULE_VERSION=v${version}" - "--dart-define=POLYCULE_IS_STABLE=true" - "--no-tree-shake-icons" - ]; - - postInstall = '' - # Install desktop files and icons from the source - install -Dm644 linux/business.braid.polycule.desktop $out/share/applications/polycule.desktop - install -Dm644 assets/logo/logo-circle.png $out/share/pixmaps/polycule.png - - # Update desktop file to use correct executable name - substituteInPlace $out/share/applications/polycule.desktop \ - --replace 'Exec=business.braid.polycule' 'Exec=polycule' - - # Create a symlink with the expected name - ln -sf $out/bin/polycule $out/bin/business.braid.polycule - ''; - - meta = with lib; { - description = "A geeky and efficient [matrix] client for power users"; - longDescription = '' - Polycule is a modern Matrix client built with Flutter, designed for power users - who want a fast, efficient, and feature-rich Matrix experience. - ''; - homepage = "https://polycule.im/"; - license = licenses.eupl12; - maintainers = []; - platforms = ["x86_64-linux" "aarch64-linux"]; - sourceProvenance = with sourceTypes; [fromSource]; - mainProgram = "polycule"; - }; -} diff --git a/modules/common-modules/pkgs/polycule/polycule-pubspec.lock.json b/modules/common-modules/pkgs/polycule/polycule-pubspec.lock.json deleted file mode 100644 index e119fa2..0000000 --- a/modules/common-modules/pkgs/polycule/polycule-pubspec.lock.json +++ /dev/null @@ -1,2459 +0,0 @@ -{ - "packages": { - "_fe_analyzer_shared": { - "dependency": "transitive", - "description": { - "name": "_fe_analyzer_shared", - "sha256": "da0d9209ca76bde579f2da330aeb9df62b6319c834fa7baae052021b0462401f", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "85.0.0" - }, - "analyzer": { - "dependency": "transitive", - "description": { - "name": "analyzer", - "sha256": "974859dc0ff5f37bc4313244b3218c791810d03ab3470a579580279ba971a48d", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "7.7.1" - }, - "animations": { - "dependency": "direct main", - "description": { - "name": "animations", - "sha256": "d3d6dcfb218225bbe68e87ccf6378bbb2e32a94900722c5f81611dad089911cb", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.0.11" - }, - "app_links": { - "dependency": "direct main", - "description": { - "name": "app_links", - "sha256": "85ed8fc1d25a76475914fff28cc994653bd900bc2c26e4b57a49e097febb54ba", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "6.4.0" - }, - "app_links_linux": { - "dependency": "transitive", - "description": { - "name": "app_links_linux", - "sha256": "f5f7173a78609f3dfd4c2ff2c95bd559ab43c80a87dc6a095921d96c05688c81", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.0.3" - }, - "app_links_platform_interface": { - "dependency": "transitive", - "description": { - "name": "app_links_platform_interface", - "sha256": "05f5379577c513b534a29ddea68176a4d4802c46180ee8e2e966257158772a3f", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.0.2" - }, - "app_links_web": { - "dependency": "transitive", - "description": { - "name": "app_links_web", - "sha256": "af060ed76183f9e2b87510a9480e56a5352b6c249778d07bd2c95fc35632a555", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.0.4" - }, - "archive": { - "dependency": "transitive", - "description": { - "name": "archive", - "sha256": "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "4.0.7" - }, - "args": { - "dependency": "transitive", - "description": { - "name": "args", - "sha256": "d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.7.0" - }, - "async": { - "dependency": "direct main", - "description": { - "name": "async", - "sha256": "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.13.0" - }, - "audio_session": { - "dependency": "transitive", - "description": { - "name": "audio_session", - "sha256": "8f96a7fecbb718cb093070f868b4cdcb8a9b1053dce342ff8ab2fde10eb9afb7", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.2.2" - }, - "barcode": { - "dependency": "transitive", - "description": { - "name": "barcode", - "sha256": "7b6729c37e3b7f34233e2318d866e8c48ddb46c1f7ad01ff7bb2a8de1da2b9f4", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.2.9" - }, - "barcode_widget": { - "dependency": "direct main", - "description": { - "name": "barcode_widget", - "sha256": "6f2c5b08659b1a5f4d88d183e6007133ea2f96e50e7b8bb628f03266c3931427", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.0.4" - }, - "base58check": { - "dependency": "transitive", - "description": { - "name": "base58check", - "sha256": "6c300dfc33e598d2fe26319e13f6243fea81eaf8204cb4c6b69ef20a625319a5", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.0.0" - }, - "blurhash_dart": { - "dependency": "direct main", - "description": { - "name": "blurhash_dart", - "sha256": "43955b6c2e30a7d440028d1af0fa185852f3534b795cc6eb81fbf397b464409f", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.2.1" - }, - "boolean_selector": { - "dependency": "transitive", - "description": { - "name": "boolean_selector", - "sha256": "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.1.2" - }, - "build_cli_annotations": { - "dependency": "transitive", - "description": { - "name": "build_cli_annotations", - "sha256": "b59d2769769efd6c9ff6d4c4cede0be115a566afc591705c2040b707534b1172", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.1.0" - }, - "camera": { - "dependency": "transitive", - "description": { - "name": "camera", - "sha256": "d6ec2cbdbe2fa8f5e0d07d8c06368fe4effa985a4a5ddade9cc58a8cd849557d", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.11.2" - }, - "camera_android_camerax": { - "dependency": "transitive", - "description": { - "name": "camera_android_camerax", - "sha256": "58b8fe843a3c83fd1273c00cb35f5a8ae507f6cc9b2029bcf7e2abba499e28d8", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.6.19+1" - }, - "camera_avfoundation": { - "dependency": "transitive", - "description": { - "name": "camera_avfoundation", - "sha256": "e4aca5bccaf897b70cac87e5fdd789393310985202442837922fd40325e2733b", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.9.21+1" - }, - "camera_platform_interface": { - "dependency": "transitive", - "description": { - "name": "camera_platform_interface", - "sha256": "2f757024a48696ff4814a789b0bd90f5660c0fb25f393ab4564fb483327930e2", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.10.0" - }, - "camera_web": { - "dependency": "transitive", - "description": { - "name": "camera_web", - "sha256": "595f28c89d1fb62d77c73c633193755b781c6d2e0ebcd8dc25b763b514e6ba8f", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.3.5" - }, - "canonical_json": { - "dependency": "transitive", - "description": { - "name": "canonical_json", - "sha256": "d6be1dd66b420c6ac9f42e3693e09edf4ff6edfee26cb4c28c1c019fdb8c0c15", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.1.2" - }, - "characters": { - "dependency": "transitive", - "description": { - "name": "characters", - "sha256": "f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.4.0" - }, - "checked_yaml": { - "dependency": "transitive", - "description": { - "name": "checked_yaml", - "sha256": "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.0.4" - }, - "cli_config": { - "dependency": "transitive", - "description": { - "name": "cli_config", - "sha256": "ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.2.0" - }, - "cli_util": { - "dependency": "transitive", - "description": { - "name": "cli_util", - "sha256": "ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.4.2" - }, - "clock": { - "dependency": "transitive", - "description": { - "name": "clock", - "sha256": "fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.1.2" - }, - "collection": { - "dependency": "direct main", - "description": { - "name": "collection", - "sha256": "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.19.1" - }, - "convert": { - "dependency": "transitive", - "description": { - "name": "convert", - "sha256": "b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "3.1.2" - }, - "coverage": { - "dependency": "transitive", - "description": { - "name": "coverage", - "sha256": "5da775aa218eaf2151c721b16c01c7676fbfdd99cebba2bf64e8b807a28ff94d", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.15.0" - }, - "cross_file": { - "dependency": "direct main", - "description": { - "name": "cross_file", - "sha256": "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.3.4+2" - }, - "crypto": { - "dependency": "transitive", - "description": { - "name": "crypto", - "sha256": "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "3.0.6" - }, - "csslib": { - "dependency": "direct main", - "description": { - "name": "csslib", - "sha256": "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.0.2" - }, - "cupertino_http": { - "dependency": "direct main", - "description": { - "name": "cupertino_http", - "sha256": "72187f715837290a63479a5b0ae709f4fedad0ed6bd0441c275eceaa02d5abae", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.3.0" - }, - "cupertino_icons": { - "dependency": "direct main", - "description": { - "name": "cupertino_icons", - "sha256": "ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.0.8" - }, - "dart_animated_emoji": { - "dependency": "direct main", - "description": { - "name": "dart_animated_emoji", - "sha256": "0e0865f1b56e2f2979e8caa09a7d693e30133050c5c677de301e6ca4d8da945e", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.1.2" - }, - "dbus": { - "dependency": "direct main", - "description": { - "name": "dbus", - "sha256": "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.7.11" - }, - "diacritic": { - "dependency": "direct main", - "description": { - "name": "diacritic", - "sha256": "12981945ec38931748836cd76f2b38773118d0baef3c68404bdfde9566147876", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.1.6" - }, - "diffutil_dart": { - "dependency": "direct main", - "description": { - "name": "diffutil_dart", - "sha256": "5e74883aedf87f3b703cb85e815bdc1ed9208b33501556e4a8a5572af9845c81", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "4.0.1" - }, - "dynamic_color": { - "dependency": "direct main", - "description": { - "name": "dynamic_color", - "sha256": "43a5a6679649a7731ab860334a5812f2067c2d9ce6452cf069c5e0c25336c17c", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.8.1" - }, - "emoji_extension": { - "dependency": "direct main", - "description": { - "name": "emoji_extension", - "sha256": "7678a3e3fca4f2dfbce02cf8d439a81e130ce303fdc1ad90f484f57fd5ce4ba1", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.2.0" - }, - "enhanced_enum": { - "dependency": "transitive", - "description": { - "name": "enhanced_enum", - "sha256": "074c5a8b9664799ca91e1e8b68003b8694cb19998671cbafd9c7779c13fcdecf", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.2.4" - }, - "equatable": { - "dependency": "transitive", - "description": { - "name": "equatable", - "sha256": "567c64b3cb4cf82397aac55f4f0cbd3ca20d77c6c03bedbc4ceaddc08904aef7", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.0.7" - }, - "fake_async": { - "dependency": "transitive", - "description": { - "name": "fake_async", - "sha256": "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.3.3" - }, - "fetch_api": { - "dependency": "transitive", - "description": { - "name": "fetch_api", - "sha256": "24cbd5616f3d4008c335c197bb90bfa0eb43b9e55c6de5c60d1f805092636034", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.3.1" - }, - "fetch_client": { - "dependency": "direct main", - "description": { - "name": "fetch_client", - "sha256": "375253f4efe64303c793fb17fe90771c591320b2ae11fb29cb5b406cc8533c00", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.1.4" - }, - "ffi": { - "dependency": "transitive", - "description": { - "name": "ffi", - "sha256": "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.1.4" - }, - "file": { - "dependency": "transitive", - "description": { - "name": "file", - "sha256": "a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "7.0.1" - }, - "file_selector": { - "dependency": "direct main", - "description": { - "name": "file_selector", - "sha256": "5019692b593455127794d5718304ff1ae15447dea286cdda9f0db2a796a1b828", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.0.3" - }, - "file_selector_android": { - "dependency": "transitive", - "description": { - "name": "file_selector_android", - "sha256": "3015702ab73987000e7ff2df5ddc99666d2bcd65cdb243f59da35729d3be6cff", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.5.1+15" - }, - "file_selector_ios": { - "dependency": "transitive", - "description": { - "name": "file_selector_ios", - "sha256": "94b98ad950b8d40d96fee8fa88640c2e4bd8afcdd4817993bd04e20310f45420", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.5.3+1" - }, - "file_selector_linux": { - "dependency": "transitive", - "description": { - "name": "file_selector_linux", - "sha256": "54cbbd957e1156d29548c7d9b9ec0c0ebb6de0a90452198683a7d23aed617a33", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.9.3+2" - }, - "file_selector_macos": { - "dependency": "transitive", - "description": { - "name": "file_selector_macos", - "sha256": "8c9250b2bd2d8d4268e39c82543bacbaca0fda7d29e0728c3c4bbb7c820fd711", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.9.4+3" - }, - "file_selector_platform_interface": { - "dependency": "transitive", - "description": { - "name": "file_selector_platform_interface", - "sha256": "a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.6.2" - }, - "file_selector_web": { - "dependency": "transitive", - "description": { - "name": "file_selector_web", - "sha256": "c4c0ea4224d97a60a7067eca0c8fd419e708ff830e0c83b11a48faf566cec3e7", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.9.4+2" - }, - "file_selector_windows": { - "dependency": "transitive", - "description": { - "name": "file_selector_windows", - "sha256": "320fcfb6f33caa90f0b58380489fc5ac05d99ee94b61aa96ec2bff0ba81d3c2b", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.9.3+4" - }, - "fixnum": { - "dependency": "transitive", - "description": { - "name": "fixnum", - "sha256": "b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.1.1" - }, - "flutter": { - "dependency": "direct main", - "description": "flutter", - "source": "sdk", - "version": "0.0.0" - }, - "flutter_adaptive_scaffold": { - "dependency": "direct main", - "description": { - "name": "flutter_adaptive_scaffold", - "sha256": "5eb1d1d174304a4e67c4bb402ed38cb4a5ebdac95ce54099e91460accb33d295", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.3.3+1" - }, - "flutter_confetti": { - "dependency": "direct main", - "description": { - "name": "flutter_confetti", - "sha256": "7e46b82ea0adc456afc91037652bbfbd52a951804fde0708822fad5d68be6398", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.5.1" - }, - "flutter_driver": { - "dependency": "direct dev", - "description": "flutter", - "source": "sdk", - "version": "0.0.0" - }, - "flutter_highlighting": { - "dependency": "direct main", - "description": { - "name": "flutter_highlighting", - "sha256": "426770b1453e8302f8cc58455ebcaad33e3049e73ca18f9d3c83554552bf3baf", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.9.0+11.8.0" - }, - "flutter_html": { - "dependency": "direct main", - "description": { - "name": "flutter_html", - "sha256": "38a2fd702ffdf3243fb7441ab58aa1bc7e6922d95a50db76534de8260638558d", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "3.0.0" - }, - "flutter_html_svg": { - "dependency": "direct main", - "description": { - "name": "flutter_html_svg", - "sha256": "76f59c238571333d95271817c3d94688b3c4dca2735552e481e49039d3efdb13", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "3.0.0" - }, - "flutter_html_table": { - "dependency": "direct main", - "description": { - "name": "flutter_html_table", - "sha256": "de15300b1f6d8014e1702e7edfdf3411f362c8fb753e89bac4c99215ea94a4d8", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "3.0.0" - }, - "flutter_keyboard_visibility": { - "dependency": "direct main", - "description": { - "name": "flutter_keyboard_visibility", - "sha256": "98664be7be0e3ffca00de50f7f6a287ab62c763fc8c762e0a21584584a3ff4f8", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "6.0.0" - }, - "flutter_keyboard_visibility_linux": { - "dependency": "transitive", - "description": { - "name": "flutter_keyboard_visibility_linux", - "sha256": "6fba7cd9bb033b6ddd8c2beb4c99ad02d728f1e6e6d9b9446667398b2ac39f08", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.0.0" - }, - "flutter_keyboard_visibility_macos": { - "dependency": "transitive", - "description": { - "name": "flutter_keyboard_visibility_macos", - "sha256": "c5c49b16fff453dfdafdc16f26bdd8fb8d55812a1d50b0ce25fc8d9f2e53d086", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.0.0" - }, - "flutter_keyboard_visibility_platform_interface": { - "dependency": "transitive", - "description": { - "name": "flutter_keyboard_visibility_platform_interface", - "sha256": "e43a89845873f7be10cb3884345ceb9aebf00a659f479d1c8f4293fcb37022a4", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.0.0" - }, - "flutter_keyboard_visibility_web": { - "dependency": "transitive", - "description": { - "name": "flutter_keyboard_visibility_web", - "sha256": "d3771a2e752880c79203f8d80658401d0c998e4183edca05a149f5098ce6e3d1", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.0.0" - }, - "flutter_keyboard_visibility_windows": { - "dependency": "transitive", - "description": { - "name": "flutter_keyboard_visibility_windows", - "sha256": "fc4b0f0b6be9b93ae527f3d527fb56ee2d918cd88bbca438c478af7bcfd0ef73", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.0.0" - }, - "flutter_launcher_icons": { - "dependency": "direct dev", - "description": { - "name": "flutter_launcher_icons", - "sha256": "10f13781741a2e3972126fae08393d3c4e01fa4cd7473326b94b72cf594195e7", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.14.4" - }, - "flutter_layout_grid": { - "dependency": "transitive", - "description": { - "name": "flutter_layout_grid", - "sha256": "739e568db97af031d528dfd8a80d333df0e5a310a126e087690fa42cd61dfb5f", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.0.8" - }, - "flutter_lints": { - "dependency": "direct dev", - "description": { - "name": "flutter_lints", - "sha256": "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "6.0.0" - }, - "flutter_local_notifications": { - "dependency": "direct main", - "description": { - "name": "flutter_local_notifications", - "sha256": "20ca0a9c82ce0c855ac62a2e580ab867f3fbea82680a90647f7953832d0850ae", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "19.4.0" - }, - "flutter_local_notifications_linux": { - "dependency": "transitive", - "description": { - "name": "flutter_local_notifications_linux", - "sha256": "e3c277b2daab8e36ac5a6820536668d07e83851aeeb79c446e525a70710770a5", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "6.0.0" - }, - "flutter_local_notifications_platform_interface": { - "dependency": "transitive", - "description": { - "name": "flutter_local_notifications_platform_interface", - "sha256": "277d25d960c15674ce78ca97f57d0bae2ee401c844b6ac80fcd972a9c99d09fe", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "9.1.0" - }, - "flutter_local_notifications_windows": { - "dependency": "transitive", - "description": { - "name": "flutter_local_notifications_windows", - "sha256": "ed46d7ae4ec9d19e4c8fa2badac5fe27ba87a3fe387343ce726f927af074ec98", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.0.2" - }, - "flutter_localizations": { - "dependency": "direct main", - "description": "flutter", - "source": "sdk", - "version": "0.0.0" - }, - "flutter_openssl_crypto": { - "dependency": "direct main", - "description": { - "name": "flutter_openssl_crypto", - "sha256": "293b4fcda13ab0710645a16e82f3d5b7de19bfc0ab2d06bcdb87637222eda5e1", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.5.0" - }, - "flutter_plugin_android_lifecycle": { - "dependency": "transitive", - "description": { - "name": "flutter_plugin_android_lifecycle", - "sha256": "6382ce712ff69b0f719640ce957559dde459e55ecd433c767e06d139ddf16cab", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.0.29" - }, - "flutter_rust_bridge": { - "dependency": "transitive", - "description": { - "name": "flutter_rust_bridge", - "sha256": "b416ff56002789e636244fb4cc449f587656eff995e5a7169457eb0593fcaddb", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.10.0" - }, - "flutter_secure_storage": { - "dependency": "direct main", - "description": { - "name": "flutter_secure_storage", - "sha256": "f7eceb0bc6f4fd0441e29d43cab9ac2a1c5ffd7ea7b64075136b718c46954874", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "10.0.0-beta.4" - }, - "flutter_secure_storage_darwin": { - "dependency": "transitive", - "description": { - "name": "flutter_secure_storage_darwin", - "sha256": "f226f2a572bed96bc6542198ebaec227150786e34311d455a7e2d3d06d951845", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.1.0" - }, - "flutter_secure_storage_linux": { - "dependency": "transitive", - "description": { - "name": "flutter_secure_storage_linux", - "sha256": "9b4b73127e857cd3117d43a70fa3dddadb6e0b253be62e6a6ab85caa0742182c", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.0.1" - }, - "flutter_secure_storage_platform_interface": { - "dependency": "transitive", - "description": { - "name": "flutter_secure_storage_platform_interface", - "sha256": "8ceea1223bee3c6ac1a22dabd8feefc550e4729b3675de4b5900f55afcb435d6", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.0.1" - }, - "flutter_secure_storage_web": { - "dependency": "transitive", - "description": { - "name": "flutter_secure_storage_web", - "sha256": "4c3f233e739545c6cb09286eeec1cc4744138372b985113acc904f7263bef517", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.0.0" - }, - "flutter_secure_storage_windows": { - "dependency": "transitive", - "description": { - "name": "flutter_secure_storage_windows", - "sha256": "ff32af20f70a8d0e59b2938fc92de35b54a74671041c814275afd80e27df9f21", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "4.0.0" - }, - "flutter_svg": { - "dependency": "direct main", - "description": { - "name": "flutter_svg", - "sha256": "cd57f7969b4679317c17af6fd16ee233c1e60a82ed209d8a475c54fd6fd6f845", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.2.0" - }, - "flutter_test": { - "dependency": "direct dev", - "description": "flutter", - "source": "sdk", - "version": "0.0.0" - }, - "flutter_typeahead": { - "dependency": "direct main", - "description": { - "name": "flutter_typeahead", - "sha256": "d64712c65db240b1057559b952398ebb6e498077baeebf9b0731dade62438a6d", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "5.2.0" - }, - "flutter_vodozemac": { - "dependency": "direct main", - "description": { - "name": "flutter_vodozemac", - "sha256": "2405ca121b84d1cd83200a14021022e1691b123a23bcefc36adc7740cefbc1f9", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.2.2" - }, - "flutter_web_plugins": { - "dependency": "transitive", - "description": "flutter", - "source": "sdk", - "version": "0.0.0" - }, - "flutter_zxing": { - "dependency": "direct main", - "description": { - "name": "flutter_zxing", - "sha256": "dbcd89da2c9aa84f48d7d7e1ba436825f8656a69b142abb7bcdb7c2d9c22d48c", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.2.1" - }, - "frontend_server_client": { - "dependency": "transitive", - "description": { - "name": "frontend_server_client", - "sha256": "f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "4.0.0" - }, - "fuchsia_remote_debug_protocol": { - "dependency": "transitive", - "description": "flutter", - "source": "sdk", - "version": "0.0.0" - }, - "glob": { - "dependency": "transitive", - "description": { - "name": "glob", - "sha256": "c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.1.3" - }, - "go_router": { - "dependency": "direct main", - "description": { - "name": "go_router", - "sha256": "8b1f37dfaf6e958c6b872322db06f946509433bec3de753c3491a42ae9ec2b48", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "16.1.0" - }, - "gtk": { - "dependency": "transitive", - "description": { - "name": "gtk", - "sha256": "e8ce9ca4b1df106e4d72dad201d345ea1a036cc12c360f1a7d5a758f78ffa42c", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.1.0" - }, - "highlighting": { - "dependency": "direct main", - "description": { - "name": "highlighting", - "sha256": "196005ed9c98ee559939fcecd466fa941b9e99b3a93394691b86780ad4da50f3", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.9.0+11.8.0" - }, - "html": { - "dependency": "direct main", - "description": { - "name": "html", - "sha256": "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.15.6" - }, - "html_unescape": { - "dependency": "transitive", - "description": { - "name": "html_unescape", - "sha256": "15362d7a18f19d7b742ef8dcb811f5fd2a2df98db9f80ea393c075189e0b61e3", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.0.0" - }, - "http": { - "dependency": "direct main", - "description": { - "name": "http", - "sha256": "bb2ce4590bc2667c96f318d68cac1b5a7987ec819351d32b1c987239a815e007", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.5.0" - }, - "http_parser": { - "dependency": "transitive", - "description": { - "name": "http_parser", - "sha256": "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "4.1.2" - }, - "http_profile": { - "dependency": "transitive", - "description": { - "name": "http_profile", - "sha256": "7e679e355b09aaee2ab5010915c932cce3f2d1c11c3b2dc177891687014ffa78", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.1.0" - }, - "image": { - "dependency": "direct main", - "description": { - "name": "image", - "sha256": "4e973fcf4caae1a4be2fa0a13157aa38a8f9cb049db6529aa00b4d71abc4d928", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "4.5.4" - }, - "image_picker": { - "dependency": "direct main", - "description": { - "name": "image_picker", - "sha256": "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.1.2" - }, - "image_picker_android": { - "dependency": "transitive", - "description": { - "name": "image_picker_android", - "sha256": "b08e9a04d0f8d91f4a6e767a745b9871bfbc585410205c311d0492de20a7ccd6", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.8.12+25" - }, - "image_picker_for_web": { - "dependency": "transitive", - "description": { - "name": "image_picker_for_web", - "sha256": "717eb042ab08c40767684327be06a5d8dbb341fe791d514e4b92c7bbe1b7bb83", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "3.0.6" - }, - "image_picker_ios": { - "dependency": "transitive", - "description": { - "name": "image_picker_ios", - "sha256": "05da758e67bc7839e886b3959848aa6b44ff123ab4b28f67891008afe8ef9100", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.8.12+2" - }, - "image_picker_linux": { - "dependency": "transitive", - "description": { - "name": "image_picker_linux", - "sha256": "34a65f6740df08bbbeb0a1abd8e6d32107941fd4868f67a507b25601651022c9", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.2.1+2" - }, - "image_picker_macos": { - "dependency": "transitive", - "description": { - "name": "image_picker_macos", - "sha256": "1b90ebbd9dcf98fb6c1d01427e49a55bd96b5d67b8c67cf955d60a5de74207c1", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.2.1+2" - }, - "image_picker_platform_interface": { - "dependency": "transitive", - "description": { - "name": "image_picker_platform_interface", - "sha256": "886d57f0be73c4b140004e78b9f28a8914a09e50c2d816bdd0520051a71236a0", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.10.1" - }, - "image_picker_windows": { - "dependency": "transitive", - "description": { - "name": "image_picker_windows", - "sha256": "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.2.1+1" - }, - "import_sorter": { - "dependency": "direct main", - "description": { - "name": "import_sorter", - "sha256": "eb15738ccead84e62c31e0208ea4e3104415efcd4972b86906ca64a1187d0836", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "4.6.0" - }, - "integration_test": { - "dependency": "direct dev", - "description": "flutter", - "source": "sdk", - "version": "0.0.0" - }, - "intl": { - "dependency": "direct main", - "description": { - "name": "intl", - "sha256": "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.20.2" - }, - "io": { - "dependency": "transitive", - "description": { - "name": "io", - "sha256": "dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.0.5" - }, - "js": { - "dependency": "transitive", - "description": { - "name": "js", - "sha256": "f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.6.7" - }, - "json_annotation": { - "dependency": "transitive", - "description": { - "name": "json_annotation", - "sha256": "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "4.9.0" - }, - "just_audio": { - "dependency": "direct main", - "description": { - "name": "just_audio", - "sha256": "679637a3ec5b6e00f36472f5a3663667df00ee4822cbf5dafca0f568c710960a", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.10.4" - }, - "just_audio_media_kit": { - "dependency": "direct main", - "description": { - "name": "just_audio_media_kit", - "sha256": "f3cf04c3a50339709e87e90b4e841eef4364ab4be2bdbac0c54cc48679f84d23", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.1.0" - }, - "just_audio_platform_interface": { - "dependency": "transitive", - "description": { - "name": "just_audio_platform_interface", - "sha256": "2532c8d6702528824445921c5ff10548b518b13f808c2e34c2fd54793b999a6a", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "4.6.0" - }, - "just_audio_web": { - "dependency": "transitive", - "description": { - "name": "just_audio_web", - "sha256": "6ba8a2a7e87d57d32f0f7b42856ade3d6a9fbe0f1a11fabae0a4f00bb73f0663", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.4.16" - }, - "just_waveform": { - "dependency": "direct main", - "description": { - "name": "just_waveform", - "sha256": "8c65acd24f13b866e3377f07f8869e823f3f2d8b734938f4e6688075af40b4f2", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.0.7" - }, - "leak_tracker": { - "dependency": "transitive", - "description": { - "name": "leak_tracker", - "sha256": "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "10.0.9" - }, - "leak_tracker_flutter_testing": { - "dependency": "transitive", - "description": { - "name": "leak_tracker_flutter_testing", - "sha256": "f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "3.0.9" - }, - "leak_tracker_testing": { - "dependency": "transitive", - "description": { - "name": "leak_tracker_testing", - "sha256": "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "3.0.1" - }, - "linkify": { - "dependency": "direct main", - "description": { - "name": "linkify", - "sha256": "4139ea77f4651ab9c315b577da2dd108d9aa0bd84b5d03d33323f1970c645832", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "5.0.0" - }, - "lints": { - "dependency": "transitive", - "description": { - "name": "lints", - "sha256": "a5e2b223cb7c9c8efdc663ef484fdd95bb243bff242ef5b13e26883547fce9a0", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "6.0.0" - }, - "list_counter": { - "dependency": "transitive", - "description": { - "name": "list_counter", - "sha256": "c447ae3dfcd1c55f0152867090e67e219d42fe6d4f2807db4bbe8b8d69912237", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.0.2" - }, - "locale_names": { - "dependency": "direct main", - "description": { - "name": "locale_names", - "sha256": "7a89ca54072f4f13d0f5df5a9ba69337554bf2fd057d1dd2a238898f3f159374", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.1.1" - }, - "logging": { - "dependency": "transitive", - "description": { - "name": "logging", - "sha256": "c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.3.0" - }, - "lottie": { - "dependency": "direct main", - "description": { - "name": "lottie", - "sha256": "c5fa04a80a620066c15cf19cc44773e19e9b38e989ff23ea32e5903ef1015950", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "3.3.1" - }, - "markdown": { - "dependency": "transitive", - "description": { - "name": "markdown", - "sha256": "935e23e1ff3bc02d390bad4d4be001208ee92cc217cb5b5a6c19bc14aaa318c1", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "7.3.0" - }, - "matcher": { - "dependency": "transitive", - "description": { - "name": "matcher", - "sha256": "dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.12.17" - }, - "material_color_utilities": { - "dependency": "transitive", - "description": { - "name": "material_color_utilities", - "sha256": "f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.11.1" - }, - "matrix": { - "dependency": "direct main", - "description": { - "path": ".", - "ref": "braid/msc3861-native-oidc", - "resolved-ref": "82ad90573e0e5e1ccb2cf1e669a5861bd6db351c", - "url": "https://github.com/TheOneWithTheBraid/matrix-dart-sdk.git" - }, - "source": "git", - "version": "1.1.0" - }, - "matrix_homeserver_recommendations": { - "dependency": "direct main", - "description": { - "name": "matrix_homeserver_recommendations", - "sha256": "48cd67146dd80b925c1cce1604da4712e7963b490d31801bad70b51ff8e30cd2", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.4.1" - }, - "media_kit": { - "dependency": "direct main", - "description": { - "path": "media_kit", - "ref": "braid/stub-template", - "resolved-ref": "215972e56ceb6036b51d1dc8803d5e0ab489bfe1", - "url": "https://github.com/TheOneWithTheBraid/media-kit.git" - }, - "source": "git", - "version": "1.2.0" - }, - "media_kit_libs_android_video": { - "dependency": "direct overridden", - "description": { - "path": "libs/android/media_kit_libs_android_video", - "ref": "main", - "resolved-ref": "ad84c59faa2b871926cb31516bdeec65d7676884", - "url": "https://github.com/Predidit/media-kit.git" - }, - "source": "git", - "version": "1.3.6" - }, - "media_kit_libs_ios_video": { - "dependency": "transitive", - "description": { - "name": "media_kit_libs_ios_video", - "sha256": "b5382994eb37a4564c368386c154ad70ba0cc78dacdd3fb0cd9f30db6d837991", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.1.4" - }, - "media_kit_libs_linux": { - "dependency": "transitive", - "description": { - "name": "media_kit_libs_linux", - "sha256": "2b473399a49ec94452c4d4ae51cfc0f6585074398d74216092bf3d54aac37ecf", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.2.1" - }, - "media_kit_libs_macos_video": { - "dependency": "transitive", - "description": { - "name": "media_kit_libs_macos_video", - "sha256": "f26aa1452b665df288e360393758f84b911f70ffb3878032e1aabba23aa1032d", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.1.4" - }, - "media_kit_libs_video": { - "dependency": "direct main", - "description": { - "name": "media_kit_libs_video", - "sha256": "958cc55e7065d9d01f52a2842dab2a0812a92add18489f1006d864fb5e42a3ef", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.0.6" - }, - "media_kit_libs_windows_video": { - "dependency": "transitive", - "description": { - "name": "media_kit_libs_windows_video", - "sha256": "dff76da2778729ab650229e6b4ec6ec111eb5151431002cbd7ea304ff1f112ab", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.0.11" - }, - "media_kit_video": { - "dependency": "direct main", - "description": { - "name": "media_kit_video", - "sha256": "a656a9463298c1adc64c57f2d012874f7f2900f0c614d9545a3e7b8bb9e2137b", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.3.0" - }, - "media_store_plus": { - "dependency": "direct main", - "description": { - "name": "media_store_plus", - "sha256": "4b4971365e00a4ed9fde14abf40d7c27475b66b8bba9bf43478ae2ecb449df20", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.1.3" - }, - "meta": { - "dependency": "transitive", - "description": { - "name": "meta", - "sha256": "e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.16.0" - }, - "mime": { - "dependency": "direct main", - "description": { - "name": "mime", - "sha256": "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.0.0" - }, - "objective_c": { - "dependency": "transitive", - "description": { - "name": "objective_c", - "sha256": "9f034ba1eeca53ddb339bc8f4813cb07336a849cd735559b60cdc068ecce2dc7", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "7.1.0" - }, - "package_config": { - "dependency": "transitive", - "description": { - "name": "package_config", - "sha256": "f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.2.0" - }, - "package_info_plus": { - "dependency": "transitive", - "description": { - "name": "package_info_plus", - "sha256": "16eee997588c60225bda0488b6dcfac69280a6b7a3cf02c741895dd370a02968", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "8.3.1" - }, - "package_info_plus_platform_interface": { - "dependency": "transitive", - "description": { - "name": "package_info_plus_platform_interface", - "sha256": "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "3.2.1" - }, - "path": { - "dependency": "transitive", - "description": { - "name": "path", - "sha256": "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.9.1" - }, - "path_parsing": { - "dependency": "transitive", - "description": { - "name": "path_parsing", - "sha256": "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.1.0" - }, - "path_provider": { - "dependency": "direct main", - "description": { - "name": "path_provider", - "sha256": "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.1.5" - }, - "path_provider_android": { - "dependency": "transitive", - "description": { - "name": "path_provider_android", - "sha256": "d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.2.17" - }, - "path_provider_foundation": { - "dependency": "transitive", - "description": { - "name": "path_provider_foundation", - "sha256": "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.4.1" - }, - "path_provider_linux": { - "dependency": "transitive", - "description": { - "name": "path_provider_linux", - "sha256": "f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.2.1" - }, - "path_provider_platform_interface": { - "dependency": "transitive", - "description": { - "name": "path_provider_platform_interface", - "sha256": "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.1.2" - }, - "path_provider_windows": { - "dependency": "transitive", - "description": { - "name": "path_provider_windows", - "sha256": "bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.3.0" - }, - "petitparser": { - "dependency": "transitive", - "description": { - "name": "petitparser", - "sha256": "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "6.1.0" - }, - "platform": { - "dependency": "transitive", - "description": { - "name": "platform", - "sha256": "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "3.1.6" - }, - "plugin_platform_interface": { - "dependency": "transitive", - "description": { - "name": "plugin_platform_interface", - "sha256": "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.1.8" - }, - "pointer_interceptor": { - "dependency": "transitive", - "description": { - "name": "pointer_interceptor", - "sha256": "57210410680379aea8b1b7ed6ae0c3ad349bfd56fe845b8ea934a53344b9d523", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.10.1+2" - }, - "pointer_interceptor_ios": { - "dependency": "transitive", - "description": { - "name": "pointer_interceptor_ios", - "sha256": "a6906772b3205b42c44614fcea28f818b1e5fdad73a4ca742a7bd49818d9c917", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.10.1" - }, - "pointer_interceptor_platform_interface": { - "dependency": "transitive", - "description": { - "name": "pointer_interceptor_platform_interface", - "sha256": "0597b0560e14354baeb23f8375cd612e8bd4841bf8306ecb71fcd0bb78552506", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.10.0+1" - }, - "pointer_interceptor_web": { - "dependency": "transitive", - "description": { - "name": "pointer_interceptor_web", - "sha256": "460b600e71de6fcea2b3d5f662c92293c049c4319e27f0829310e5a953b3ee2a", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.10.3" - }, - "pool": { - "dependency": "transitive", - "description": { - "name": "pool", - "sha256": "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.5.1" - }, - "posix": { - "dependency": "transitive", - "description": { - "name": "posix", - "sha256": "6323a5b0fa688b6a010df4905a56b00181479e6d10534cecfecede2aa55add61", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "6.0.3" - }, - "process": { - "dependency": "transitive", - "description": { - "name": "process", - "sha256": "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "5.0.3" - }, - "pub_semver": { - "dependency": "transitive", - "description": { - "name": "pub_semver", - "sha256": "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.2.0" - }, - "qr": { - "dependency": "transitive", - "description": { - "name": "qr", - "sha256": "5a1d2586170e172b8a8c8470bbbffd5eb0cd38a66c0d77155ea138d3af3a4445", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "3.0.2" - }, - "quiver": { - "dependency": "transitive", - "description": { - "name": "quiver", - "sha256": "ea0b925899e64ecdfbf9c7becb60d5b50e706ade44a85b2363be2a22d88117d2", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "3.2.2" - }, - "random_string": { - "dependency": "transitive", - "description": { - "name": "random_string", - "sha256": "03b52435aae8cbdd1056cf91bfc5bf845e9706724dd35ae2e99fa14a1ef79d02", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.3.1" - }, - "receive_sharing_intent": { - "dependency": "direct main", - "description": { - "name": "receive_sharing_intent", - "sha256": "ec76056e4d258ad708e76d85591d933678625318e411564dcb9059048ca3a593", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.8.1" - }, - "rxdart": { - "dependency": "transitive", - "description": { - "name": "rxdart", - "sha256": "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.28.0" - }, - "safe_local_storage": { - "dependency": "transitive", - "description": { - "name": "safe_local_storage", - "sha256": "e9a21b6fec7a8aa62cc2585ff4c1b127df42f3185adbd2aca66b47abe2e80236", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.0.1" - }, - "screen_brightness_android": { - "dependency": "transitive", - "description": { - "name": "screen_brightness_android", - "sha256": "fb5fa43cb89d0c9b8534556c427db1e97e46594ac5d66ebdcf16063b773d54ed", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.1.2" - }, - "screen_brightness_platform_interface": { - "dependency": "transitive", - "description": { - "name": "screen_brightness_platform_interface", - "sha256": "737bd47b57746bc4291cab1b8a5843ee881af499514881b0247ec77447ee769c", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.1.0" - }, - "sdp_transform": { - "dependency": "transitive", - "description": { - "name": "sdp_transform", - "sha256": "73e412a5279a5c2de74001535208e20fff88f225c9a4571af0f7146202755e45", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.3.2" - }, - "sentry": { - "dependency": "direct main", - "description": { - "name": "sentry", - "sha256": "d9f3dcf1ecdd600cf9ce134f622383adde5423ecfdaf0ca9b20fbc1c44849337", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "9.6.0" - }, - "share_plus": { - "dependency": "direct main", - "description": { - "name": "share_plus", - "sha256": "d7dc0630a923883c6328ca31b89aa682bacbf2f8304162d29f7c6aaff03a27a1", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "11.1.0" - }, - "share_plus_platform_interface": { - "dependency": "transitive", - "description": { - "name": "share_plus_platform_interface", - "sha256": "88023e53a13429bd65d8e85e11a9b484f49d4c190abbd96c7932b74d6927cc9a", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "6.1.0" - }, - "sky_engine": { - "dependency": "transitive", - "description": "flutter", - "source": "sdk", - "version": "0.0.0" - }, - "slugify": { - "dependency": "transitive", - "description": { - "name": "slugify", - "sha256": "b272501565cb28050cac2d96b7bf28a2d24c8dae359280361d124f3093d337c3", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.0.0" - }, - "source_map_stack_trace": { - "dependency": "transitive", - "description": { - "name": "source_map_stack_trace", - "sha256": "c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.1.2" - }, - "source_maps": { - "dependency": "transitive", - "description": { - "name": "source_maps", - "sha256": "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.10.13" - }, - "source_span": { - "dependency": "transitive", - "description": { - "name": "source_span", - "sha256": "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.10.1" - }, - "sprintf": { - "dependency": "transitive", - "description": { - "name": "sprintf", - "sha256": "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "7.0.0" - }, - "sqflite": { - "dependency": "direct main", - "description": { - "name": "sqflite", - "sha256": "e2297b1da52f127bc7a3da11439985d9b536f75070f3325e62ada69a5c585d03", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.4.2" - }, - "sqflite_android": { - "dependency": "transitive", - "description": { - "name": "sqflite_android", - "sha256": "2b3070c5fa881839f8b402ee4a39c1b4d561704d4ebbbcfb808a119bc2a1701b", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.4.1" - }, - "sqflite_common": { - "dependency": "transitive", - "description": { - "name": "sqflite_common", - "sha256": "6ef422a4525ecc601db6c0a2233ff448c731307906e92cabc9ba292afaae16a6", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.5.6" - }, - "sqflite_common_ffi": { - "dependency": "direct main", - "description": { - "name": "sqflite_common_ffi", - "sha256": "9faa2fedc5385ef238ce772589f7718c24cdddd27419b609bb9c6f703ea27988", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.3.6" - }, - "sqflite_darwin": { - "dependency": "transitive", - "description": { - "name": "sqflite_darwin", - "sha256": "279832e5cde3fe99e8571879498c9211f3ca6391b0d818df4e17d9fff5c6ccb3", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.4.2" - }, - "sqflite_platform_interface": { - "dependency": "transitive", - "description": { - "name": "sqflite_platform_interface", - "sha256": "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.4.0" - }, - "sqlcipher_flutter_libs": { - "dependency": "direct main", - "description": { - "name": "sqlcipher_flutter_libs", - "sha256": "dd1fcc74d5baf3c36ad53e2652b2d06c9f8747494a3ccde0076e88b159dfe622", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.6.8" - }, - "sqlite3": { - "dependency": "transitive", - "description": { - "name": "sqlite3", - "sha256": "f393d92c71bdcc118d6203d07c991b9be0f84b1a6f89dd4f7eed348131329924", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.9.0" - }, - "stack_trace": { - "dependency": "transitive", - "description": { - "name": "stack_trace", - "sha256": "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.12.1" - }, - "stream_channel": { - "dependency": "transitive", - "description": { - "name": "stream_channel", - "sha256": "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.1.4" - }, - "stream_transform": { - "dependency": "transitive", - "description": { - "name": "stream_transform", - "sha256": "ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.1.1" - }, - "string_scanner": { - "dependency": "transitive", - "description": { - "name": "string_scanner", - "sha256": "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.4.1" - }, - "sync_http": { - "dependency": "transitive", - "description": { - "name": "sync_http", - "sha256": "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.3.1" - }, - "synchronized": { - "dependency": "transitive", - "description": { - "name": "synchronized", - "sha256": "c254ade258ec8282947a0acbbc90b9575b4f19673533ee46f2f6e9b3aeefd7c0", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "3.4.0" - }, - "term_glyph": { - "dependency": "transitive", - "description": { - "name": "term_glyph", - "sha256": "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.2.2" - }, - "test_api": { - "dependency": "transitive", - "description": { - "name": "test_api", - "sha256": "fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.7.4" - }, - "test_core": { - "dependency": "transitive", - "description": { - "name": "test_core", - "sha256": "84d17c3486c8dfdbe5e12a50c8ae176d15e2a771b96909a9442b40173649ccaa", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.6.8" - }, - "timezone": { - "dependency": "transitive", - "description": { - "name": "timezone", - "sha256": "dd14a3b83cfd7cb19e7888f1cbc20f258b8d71b54c06f79ac585f14093a287d1", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.10.1" - }, - "tint": { - "dependency": "transitive", - "description": { - "name": "tint", - "sha256": "9652d9a589f4536d5e392cf790263d120474f15da3cf1bee7f1fdb31b4de5f46", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.0.1" - }, - "tuple": { - "dependency": "transitive", - "description": { - "name": "tuple", - "sha256": "a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.0.2" - }, - "typed_data": { - "dependency": "transitive", - "description": { - "name": "typed_data", - "sha256": "f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.4.0" - }, - "unifiedpush": { - "dependency": "direct main", - "description": { - "name": "unifiedpush", - "sha256": "1418375efb580af9640de4eaf4209cb6481f9a48792648ced3051f30e67d9568", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "6.0.2" - }, - "unifiedpush_android": { - "dependency": "transitive", - "description": { - "name": "unifiedpush_android", - "sha256": "2f25db8eb2fc3183bf2e43db89fff20b2587adc1c361e1d1e06b223a0d45b50a", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "3.1.1" - }, - "unifiedpush_platform_interface": { - "dependency": "transitive", - "description": { - "name": "unifiedpush_platform_interface", - "sha256": "bb49d2748211520e35e0374ab816faa8a2c635267e71909d334ad868d532eba5", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "3.0.1" - }, - "universal_platform": { - "dependency": "transitive", - "description": { - "name": "universal_platform", - "sha256": "64e16458a0ea9b99260ceb5467a214c1f298d647c659af1bff6d3bf82536b1ec", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.1.0" - }, - "unorm_dart": { - "dependency": "direct main", - "description": { - "name": "unorm_dart", - "sha256": "5b35bff83fce4d76467641438f9e867dc9bcfdb8c1694854f230579d68cd8f4b", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.2.0" - }, - "uri_parser": { - "dependency": "transitive", - "description": { - "name": "uri_parser", - "sha256": "ff4d2c720aca3f4f7d5445e23b11b2d15ef8af5ddce5164643f38ff962dcb270", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "3.0.0" - }, - "url_launcher": { - "dependency": "direct main", - "description": { - "name": "url_launcher", - "sha256": "f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "6.3.2" - }, - "url_launcher_android": { - "dependency": "transitive", - "description": { - "name": "url_launcher_android", - "sha256": "0aedad096a85b49df2e4725fa32118f9fa580f3b14af7a2d2221896a02cd5656", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "6.3.17" - }, - "url_launcher_ios": { - "dependency": "transitive", - "description": { - "name": "url_launcher_ios", - "sha256": "7f2022359d4c099eea7df3fdf739f7d3d3b9faf3166fb1dd390775176e0b76cb", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "6.3.3" - }, - "url_launcher_linux": { - "dependency": "transitive", - "description": { - "name": "url_launcher_linux", - "sha256": "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "3.2.1" - }, - "url_launcher_macos": { - "dependency": "transitive", - "description": { - "name": "url_launcher_macos", - "sha256": "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "3.2.2" - }, - "url_launcher_platform_interface": { - "dependency": "transitive", - "description": { - "name": "url_launcher_platform_interface", - "sha256": "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.3.2" - }, - "url_launcher_web": { - "dependency": "transitive", - "description": { - "name": "url_launcher_web", - "sha256": "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.4.1" - }, - "url_launcher_windows": { - "dependency": "transitive", - "description": { - "name": "url_launcher_windows", - "sha256": "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "3.1.4" - }, - "uuid": { - "dependency": "transitive", - "description": { - "name": "uuid", - "sha256": "a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "4.5.1" - }, - "vector_graphics": { - "dependency": "transitive", - "description": { - "name": "vector_graphics", - "sha256": "a4f059dc26fc8295b5921376600a194c4ec7d55e72f2fe4c7d2831e103d461e6", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.1.19" - }, - "vector_graphics_codec": { - "dependency": "transitive", - "description": { - "name": "vector_graphics_codec", - "sha256": "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.1.13" - }, - "vector_graphics_compiler": { - "dependency": "transitive", - "description": { - "name": "vector_graphics_compiler", - "sha256": "557a315b7d2a6dbb0aaaff84d857967ce6bdc96a63dc6ee2a57ce5a6ee5d3331", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.1.17" - }, - "vector_math": { - "dependency": "transitive", - "description": { - "name": "vector_math", - "sha256": "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "2.1.4" - }, - "visibility_detector": { - "dependency": "direct main", - "description": { - "name": "visibility_detector", - "sha256": "dd5cc11e13494f432d15939c3aa8ae76844c42b723398643ce9addb88a5ed420", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.4.0+2" - }, - "vm_service": { - "dependency": "transitive", - "description": { - "name": "vm_service", - "sha256": "ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "15.0.0" - }, - "vodozemac": { - "dependency": "direct main", - "description": { - "name": "vodozemac", - "sha256": "dba14017e042748fb22d270e8ab1d3e46965b89788dd3857dba938ec07571968", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.2.0" - }, - "volume_controller": { - "dependency": "transitive", - "description": { - "name": "volume_controller", - "sha256": "d75039e69c0d90e7810bfd47e3eedf29ff8543ea7a10392792e81f9bded7edf5", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "3.4.0" - }, - "wakelock_plus": { - "dependency": "transitive", - "description": { - "name": "wakelock_plus", - "sha256": "a474e314c3e8fb5adef1f9ae2d247e57467ad557fa7483a2b895bc1b421c5678", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.3.2" - }, - "wakelock_plus_platform_interface": { - "dependency": "transitive", - "description": { - "name": "wakelock_plus_platform_interface", - "sha256": "e10444072e50dbc4999d7316fd303f7ea53d31c824aa5eb05d7ccbdd98985207", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.2.3" - }, - "watcher": { - "dependency": "transitive", - "description": { - "name": "watcher", - "sha256": "0b7fd4a0bbc4b92641dbf20adfd7e3fd1398fe17102d94b674234563e110088a", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.1.2" - }, - "web": { - "dependency": "direct main", - "description": { - "name": "web", - "sha256": "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.1.1" - }, - "web_multiple_tab_detector": { - "dependency": "direct main", - "description": { - "name": "web_multiple_tab_detector", - "sha256": "a40d485720ea88b4e25311421d435906ba202ac33e35435403dc1c49c5ed7c4e", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "0.3.0" - }, - "web_socket": { - "dependency": "transitive", - "description": { - "name": "web_socket", - "sha256": "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.0.1" - }, - "webdriver": { - "dependency": "transitive", - "description": { - "name": "webdriver", - "sha256": "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "3.1.0" - }, - "webrtc_interface": { - "dependency": "transitive", - "description": { - "name": "webrtc_interface", - "sha256": "86fe3afc81a08481dfb25cf14a5a94e27062ecef25544783f352c914e0bbc1ca", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.2.2+hotfix.2" - }, - "win32": { - "dependency": "transitive", - "description": { - "name": "win32", - "sha256": "66814138c3562338d05613a6e368ed8cfb237ad6d64a9e9334be3f309acfca03", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "5.14.0" - }, - "xdg_directories": { - "dependency": "transitive", - "description": { - "name": "xdg_directories", - "sha256": "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "1.1.0" - }, - "xml": { - "dependency": "transitive", - "description": { - "name": "xml", - "sha256": "b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "6.5.0" - }, - "yaml": { - "dependency": "transitive", - "description": { - "name": "yaml", - "sha256": "b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce", - "url": "https://pub.dev" - }, - "source": "hosted", - "version": "3.1.3" - } - }, - "sdks": { - "dart": ">=3.8.0 <4.0.0", - "flutter": ">=3.29.0" - } -} diff --git a/modules/home-manager-modules/impermanence.nix b/modules/home-manager-modules/impermanence.nix index dc9eae9..6c75edd 100644 --- a/modules/home-manager-modules/impermanence.nix +++ b/modules/home-manager-modules/impermanence.nix @@ -8,21 +8,25 @@ in { options.impermanence = { enable = lib.mkEnableOption "impermanence for home directory"; + fallbackPersistence.enable = lib.mkOption { + type = lib.types.bool; + default = true; + }; }; config = lib.mkMerge [ (lib.mkIf config.impermanence.enable { assertions = [ { - assertion = osConfig.impermanence.enable; - message = "impermanence can not be enabled for a user when it is not enabled for a configuration"; + assertion = osConfig.host.impermanence.enable; + message = "impermanence can not be enabled for a user when it is not enabled for the system"; } ]; }) - (lib.mkIf osConfig.host.impermanence.enable { - # If impermanence is not enabled for this user but system impermanence is enabled, - # persist the entire home directory as fallback - home.persistence."/persist/home/${config.home.username}" = lib.mkIf (!cfg.enable) { + # If impermanence is not enabled for this user but system impermanence is enabled, + # persist the entire home directory as fallback + (lib.mkIf (osConfig.host.impermanence.enable && !cfg.enable && cfg.fallbackPersistence.enable) { + home.persistence."/persist/home/${config.home.username}" = { directories = ["."]; allowOther = true; }; diff --git a/modules/home-manager-modules/programs/bitwarden.nix b/modules/home-manager-modules/programs/bitwarden.nix index 5c14068..e305b6c 100644 --- a/modules/home-manager-modules/programs/bitwarden.nix +++ b/modules/home-manager-modules/programs/bitwarden.nix @@ -11,7 +11,7 @@ config = lib.mkIf config.programs.bitwarden.enable (lib.mkMerge [ { home.packages = with pkgs; [ - bitwarden + bitwarden-desktop ]; } ( diff --git a/modules/home-manager-modules/programs/default.nix b/modules/home-manager-modules/programs/default.nix index 3fff489..e70cfc8 100644 --- a/modules/home-manager-modules/programs/default.nix +++ b/modules/home-manager-modules/programs/default.nix @@ -31,6 +31,7 @@ ./freecad.nix ./onionshare.nix ./mfoc.nix + ./noita-entangled-worlds.nix ./pdfarranger.nix ./picard.nix ./qflipper.nix @@ -43,7 +44,6 @@ ./davinci-resolve.nix ./gdx-liftoff.nix ./tor-browser.nix - ./polycule.nix ./vmware-workstation.nix ]; } diff --git a/modules/home-manager-modules/programs/discord.nix b/modules/home-manager-modules/programs/discord.nix index d5d7192..71b09b2 100644 --- a/modules/home-manager-modules/programs/discord.nix +++ b/modules/home-manager-modules/programs/discord.nix @@ -1,19 +1,9 @@ { lib, - pkgs, config, ... }: { - options.programs.discord = { - enable = lib.mkEnableOption "enable discord"; - }; - config = lib.mkIf config.programs.discord.enable (lib.mkMerge [ - { - home.packages = with pkgs; [ - discord - ]; - } ( lib.mkIf config.impermanence.enable { home.persistence."/persist${config.home.homeDirectory}" = { diff --git a/modules/home-manager-modules/programs/noita-entangled-worlds.nix b/modules/home-manager-modules/programs/noita-entangled-worlds.nix new file mode 100644 index 0000000..3f3af64 --- /dev/null +++ b/modules/home-manager-modules/programs/noita-entangled-worlds.nix @@ -0,0 +1,18 @@ +{ + lib, + pkgs, + config, + ... +}: { + options = { + programs.noita-entangled-worlds = { + enable = lib.mkEnableOption "Noita Entangled Worlds multiplayer mod"; + }; + }; + + config = lib.mkIf config.programs.noita-entangled-worlds.enable { + home.packages = with pkgs; [ + noita_entangled_worlds + ]; + }; +} diff --git a/modules/home-manager-modules/programs/polycule.nix b/modules/home-manager-modules/programs/polycule.nix deleted file mode 100644 index d0aea2a..0000000 --- a/modules/home-manager-modules/programs/polycule.nix +++ /dev/null @@ -1,31 +0,0 @@ -{ - lib, - pkgs, - config, - ... -}: { - options.programs.polycule = { - enable = lib.mkEnableOption "enable polycule matrix client"; - package = lib.mkPackageOption pkgs "polycule" {}; - }; - - config = lib.mkIf config.programs.polycule.enable (lib.mkMerge [ - { - home.packages = [ - config.programs.polycule.package - ]; - } - ( - lib.mkIf config.impermanence.enable { - home.persistence."/persist${config.home.homeDirectory}" = { - # TODO: check that these are actually the correct folders - # directories = [ - # "${config.xdg.configHome}/polycule" - # "${config.xdg.dataHome}/polycule" - # "${config.xdg.cacheHome}/polycule" - # ]; - }; - } - ) - ]); -} diff --git a/modules/home-manager-modules/programs/vscode/conventionalCommits.nix b/modules/home-manager-modules/programs/vscode/conventionalCommits.nix index 5bc8124..b667c27 100644 --- a/modules/home-manager-modules/programs/vscode/conventionalCommits.nix +++ b/modules/home-manager-modules/programs/vscode/conventionalCommits.nix @@ -19,6 +19,10 @@ in { gitmoji = lib.mkEnableOption "should emoji be prompted for as a part of the commit message./"; promptScopes = lib.mkEnableOption "prompting for scopes in conventional commits"; + + promptFooter = lib.mkEnableOption "prompting for footer in conventional commits"; + + showNewVersionNotes = lib.mkEnableOption "showing new version notes for conventional commits"; }; }; config = lib.mkIf config.extraExtensions.conventionalCommits.enable { @@ -27,6 +31,8 @@ in { userSettings = { "conventionalCommits.gitmoji" = config.extraExtensions.conventionalCommits.gitmoji; "conventionalCommits.promptScopes" = config.extraExtensions.conventionalCommits.promptScopes; + "conventionalCommits.promptFooter" = config.extraExtensions.conventionalCommits.promptFooter; + "conventionalCommits.showNewVersionNotes" = config.extraExtensions.conventionalCommits.showNewVersionNotes; }; }; })); diff --git a/modules/home-manager-modules/programs/vscode/default.nix b/modules/home-manager-modules/programs/vscode/default.nix index 8f366fe..f9d83dc 100644 --- a/modules/home-manager-modules/programs/vscode/default.nix +++ b/modules/home-manager-modules/programs/vscode/default.nix @@ -16,6 +16,7 @@ ./go.nix ./evenBetterToml.nix ./openRemoteSsh.nix + ./rustAnalyzer.nix ./astroVscode.nix ./vscodeMdx.nix ./claudeDev.nix diff --git a/modules/home-manager-modules/programs/vscode/rustAnalyzer.nix b/modules/home-manager-modules/programs/vscode/rustAnalyzer.nix new file mode 100644 index 0000000..66e9ebe --- /dev/null +++ b/modules/home-manager-modules/programs/vscode/rustAnalyzer.nix @@ -0,0 +1,27 @@ +{ + lib, + pkgs, + config, + ... +}: let + pkgsRepositories = pkgs.nix-vscode-extensions.forVSCodeVersion config.programs.vscode.package.version; + pkgsRepository = pkgsRepositories.open-vsx; +in { + options.programs.vscode.profiles = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule ({config, ...}: { + options = { + extraExtensions.rustAnalyzer = { + enable = lib.mkEnableOption "should the rust-analyzer extension for vscode be enabled"; + extension = lib.mkPackageOption pkgsRepository "rust-analyzer" { + default = ["rust-lang" "rust-analyzer"]; + }; + }; + }; + config = lib.mkIf config.extraExtensions.rustAnalyzer.enable { + extensions = [ + config.extraExtensions.rustAnalyzer.extension + ]; + }; + })); + }; +} diff --git a/modules/nixos-modules/impermanence.nix b/modules/nixos-modules/impermanence.nix index 7735e97..60011cb 100644 --- a/modules/nixos-modules/impermanence.nix +++ b/modules/nixos-modules/impermanence.nix @@ -3,6 +3,39 @@ lib, ... }: { + # options.storage = { + # zfs = { + # # TODO: enable option + # # when this option is enabled we need to configure and enable disko things + + # # TODO: we need some way of managing notifications + + # # TODO: we need options to configure zfs pools + # # we should have warnings when the configured pool is missing drives + + # # TODO: dataset option that is a submodule that adds datasets to the system + # # warnings for when a dataset was created in the past on a system but it is now missing some of the options defined for it + + # # TODO: pools and datasets need to be passed to disko + # }; + + # impermanence = { + # # TODO: enable option + + # # TODO: datasets option that is a submodule that will be used to define what datasets to add to the storage system + # # We should by default create the `local`, `local/system/nix`, `local/system/root`, `persist` `persist/system/root`, and `persist/system/var/log` datasets + # # Then we should make a dataset for user folders local and persist + # # We should also create datasets for systemd modules that have have impermanence enabled for them + # # we need to figure out what options a dataset can have in zfs + # }; + + # # TODO: we should have an impermanence module for home manager that proxies its values namespaced to the user down here that matches the same interface + + # # TODO: we should have a way of enabling impermanence for a systemd config + # # these should have an option to put their folder into their own dataset (this needs to support private vs non private) + # # options for features that can be added to the dataset + # }; + options.host.impermanence.enable = lib.mkEnableOption "are we going to use impermanence on this device"; config = lib.mkMerge [ @@ -93,6 +126,7 @@ ]; }; + # TODO: this should live in leylas home manager configuration security.sudo.extraConfig = "Defaults lecture=never"; } ) diff --git a/modules/nixos-modules/server/actual/actual.nix b/modules/nixos-modules/server/actual/actual.nix new file mode 100644 index 0000000..4cca449 --- /dev/null +++ b/modules/nixos-modules/server/actual/actual.nix @@ -0,0 +1,24 @@ +{ + lib, + config, + ... +}: let + const = import ./const.nix; + dataDirectory = const.dataDirectory; +in { + options.services.actual = { + port = lib.mkOption { + type = lib.types.port; + description = "The port to listen on"; + default = 5006; + }; + }; + config = lib.mkIf config.services.actual.enable { + services.actual = { + settings = { + port = config.services.actual.port; + dataDir = dataDirectory; + }; + }; + }; +} diff --git a/modules/nixos-modules/server/actual/const.nix b/modules/nixos-modules/server/actual/const.nix index 13b068e..14b715e 100644 --- a/modules/nixos-modules/server/actual/const.nix +++ b/modules/nixos-modules/server/actual/const.nix @@ -1,3 +1,3 @@ { - dataDirectory = "/var/lib/actual/"; + dataDirectory = "/var/lib/private/actual"; } diff --git a/modules/nixos-modules/server/actual/default.nix b/modules/nixos-modules/server/actual/default.nix index 546240e..b59517b 100644 --- a/modules/nixos-modules/server/actual/default.nix +++ b/modules/nixos-modules/server/actual/default.nix @@ -1,26 +1,8 @@ { - lib, - config, - ... -}: let - const = import ./const.nix; - dataDirectory = const.dataDirectory; -in { imports = [ + ./actual.nix ./proxy.nix ./fail2ban.nix ./impermanence.nix ]; - - config = lib.mkIf config.services.actual.enable { - systemd.tmpfiles.rules = [ - "d ${dataDirectory} 2770 actual actual" - ]; - - services.actual = { - settings = { - ACTUAL_DATA_DIR = dataDirectory; - }; - }; - }; } diff --git a/modules/nixos-modules/server/actual/impermanence.nix b/modules/nixos-modules/server/actual/impermanence.nix index 5eee95a..d870789 100644 --- a/modules/nixos-modules/server/actual/impermanence.nix +++ b/modules/nixos-modules/server/actual/impermanence.nix @@ -6,11 +6,22 @@ const = import ./const.nix; dataDirectory = const.dataDirectory; in { - config = lib.mkIf (config.services.actual.enable && config.host.impermanence.enable) { + options.services.actual = { + impermanence.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.actual.enable && config.host.impermanence.enable; + }; + }; + + config = lib.mkIf config.services.actual.impermanence.enable { assertions = [ { - assertion = config.services.actual.settings.ACTUAL_DATA_DIR == dataDirectory; - message = "actual data location does not match persistence"; + assertion = config.services.actual.settings.dataDir == dataDirectory; + message = "actual data location does not match persistence\nconfig directory: ${config.services.actual.settings.dataDir}\npersistence directory: ${dataDirectory}"; + } + { + assertion = config.systemd.services.actual.serviceConfig.DynamicUser or false; + message = "actual systemd service must have DynamicUser enabled to use private directory"; } ]; environment.persistence."/persist/system/root" = { diff --git a/modules/nixos-modules/server/actual/proxy.nix b/modules/nixos-modules/server/actual/proxy.nix index 6ca51e4..9d37574 100644 --- a/modules/nixos-modules/server/actual/proxy.nix +++ b/modules/nixos-modules/server/actual/proxy.nix @@ -4,17 +4,30 @@ ... }: { options.services.actual = { - subdomain = lib.mkOption { + domain = lib.mkOption { type = lib.types.str; - default = "actual"; - description = "subdomain of base domain that actual will be hosted at"; + description = "domain that actual will be hosted at"; + default = "actual.arpa"; + }; + extraDomains = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "extra domains that should be configured for actual"; + default = []; + }; + reverseProxy.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.actual.enable && config.services.reverseProxy.enable; }; }; - config = lib.mkIf (config.services.actual.enable && config.host.reverse_proxy.enable) { - host = { - reverse_proxy.subdomains.${config.services.actual.subdomain} = { - target = "http://localhost:${toString config.services.actual.settings.port}"; + config = lib.mkIf config.services.actual.reverseProxy.enable { + services.reverseProxy.services.actual = { + target = "http://localhost:${toString config.services.actual.settings.port}"; + domain = config.services.actual.domain; + extraDomains = config.services.actual.extraDomains; + + settings = { + forwardHeaders.enable = true; }; }; }; diff --git a/modules/nixos-modules/server/bazarr/default.nix b/modules/nixos-modules/server/bazarr/default.nix index f39d940..86dbb4b 100644 --- a/modules/nixos-modules/server/bazarr/default.nix +++ b/modules/nixos-modules/server/bazarr/default.nix @@ -1,6 +1,5 @@ {...}: { imports = [ - ./proxy.nix ./impermanence.nix ]; } diff --git a/modules/nixos-modules/server/bazarr/impermanence.nix b/modules/nixos-modules/server/bazarr/impermanence.nix index 22fb0e6..70a45d1 100644 --- a/modules/nixos-modules/server/bazarr/impermanence.nix +++ b/modules/nixos-modules/server/bazarr/impermanence.nix @@ -5,7 +5,14 @@ }: let bazarr_data_directory = "/var/lib/bazarr"; in { - config = lib.mkIf (config.services.bazarr.enable && config.host.impermanence.enable) { + options.services.bazarr = { + impermanence.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.bazarr.enable && config.host.impermanence.enable; + }; + }; + + config = lib.mkIf config.services.bazarr.impermanence.enable { assertions = [ { assertion = config.services.bazarr.dataDir == bazarr_data_directory; diff --git a/modules/nixos-modules/server/bazarr/proxy.nix b/modules/nixos-modules/server/bazarr/proxy.nix deleted file mode 100644 index fe310d8..0000000 --- a/modules/nixos-modules/server/bazarr/proxy.nix +++ /dev/null @@ -1,28 +0,0 @@ -{ - lib, - config, - ... -}: { - options.services.bazarr = { - subdomain = lib.mkOption { - type = lib.types.nullOr lib.types.str; - default = null; - description = "Subdomain for reverse proxy. If null, service will be local only."; - }; - extraSubdomains = lib.mkOption { - type = lib.types.listOf lib.types.str; - default = []; - description = "Extra subdomains for reverse proxy."; - }; - }; - - config = lib.mkIf (config.services.bazarr.enable && config.services.bazarr.subdomain != null) { - host.reverse_proxy.subdomains.bazarr = { - subdomain = config.services.bazarr.subdomain; - extraSubdomains = config.services.bazarr.extraSubdomains; - target = "http://127.0.0.1:6767"; - websockets.enable = true; - forwardHeaders.enable = true; - }; - }; -} diff --git a/modules/nixos-modules/server/crab-hole/crab-hole.nix b/modules/nixos-modules/server/crab-hole/crab-hole.nix index 58ff660..d76323a 100644 --- a/modules/nixos-modules/server/crab-hole/crab-hole.nix +++ b/modules/nixos-modules/server/crab-hole/crab-hole.nix @@ -27,9 +27,19 @@ in { show_doc = lib.mkEnableOption "OpenAPI documentation (loads content from third party websites)"; downstreams = { - loopback = { - enable = lib.mkEnableOption "loopback downstream DNS server on localhost:53"; - openFirewall = lib.mkEnableOption "automatic port forwarding for the loopback downstream"; + host = { + enable = lib.mkEnableOption "host downstream DNS server accessible from network on all interfaces"; + port = lib.mkOption { + type = lib.types.port; + default = 53; + description = "Port for the host downstream DNS server to listen on."; + }; + openFirewall = lib.mkEnableOption "automatic port forwarding for the host downstream"; + disableSystemdResolved = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Whether to automatically disable systemd-resolved when using port 53. Set to false if you want to handle the conflict manually."; + }; }; }; @@ -79,9 +89,44 @@ in { default = []; description = "List of additional upstream DNS server configurations."; }; + + blocklists = { + ad_malware = { + enable = lib.mkEnableOption "Host file for blocking ads and malware"; + url = lib.mkOption { + type = lib.types.str; + default = "http://sbc.io/hosts/hosts"; + description = "URL of the ad and malware blocklist host file"; + }; + }; + }; + + extraBlocklists = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = []; + description = "Additional blocklist URLs to be added to the configuration"; + }; }; config = lib.mkIf cfg.enable { + # Assertions for proper configuration + assertions = [ + { + assertion = !(cfg.downstreams.host.enable && cfg.downstreams.host.port == 53 && config.services.resolved.enable && cfg.downstreams.host.disableSystemdResolved); + message = "crab-hole host downstream cannot use port 53 while systemd-resolved is enabled. Either disable systemd-resolved or use a different port."; + } + { + assertion = !(cfg.downstreams.host.enable && cfg.downstreams.host.port == 53 && !cfg.downstreams.host.disableSystemdResolved && config.services.resolved.enable); + message = "crab-hole host downstream is configured to use port 53 but systemd-resolved is still enabled and disableSystemdResolved is false. Set disableSystemdResolved = true or manually disable systemd-resolved."; + } + ]; + + # Automatically disable systemd-resolved if using port 53 + services.resolved.enable = lib.mkIf (cfg.downstreams.host.enable && cfg.downstreams.host.port == 53 && cfg.downstreams.host.disableSystemdResolved) (lib.mkForce false); + + # Configure DNS nameservers when disabling systemd-resolved + networking.nameservers = lib.mkIf (cfg.downstreams.host.enable && cfg.downstreams.host.port == 53 && cfg.downstreams.host.disableSystemdResolved) (lib.mkDefault ["127.0.0.1" "1.1.1.1" "8.8.8.8"]); + services.crab-hole.settings = lib.mkMerge [ { api = { @@ -91,13 +136,17 @@ in { }; downstream = cfg.extraDownstreams; upstream.name_servers = cfg.extraUpstreams; + blocklist.lists = cfg.extraBlocklists; } - (lib.mkIf cfg.downstreams.loopback.enable { + (lib.mkIf cfg.blocklists.ad_malware.enable { + blocklist.lists = [cfg.blocklists.ad_malware.url]; + }) + (lib.mkIf cfg.downstreams.host.enable { downstream = [ { protocol = "udp"; - listen = "localhost"; - port = 53; + listen = "0.0.0.0"; + port = cfg.downstreams.host.port; } ]; }) @@ -136,8 +185,8 @@ in { (lib.mkIf cfg.openFirewall { allowedTCPPorts = [cfg.port]; }) - (lib.mkIf (cfg.downstreams.loopback.enable && cfg.downstreams.loopback.openFirewall) { - allowedUDPPorts = [53]; + (lib.mkIf (cfg.downstreams.host.enable && cfg.downstreams.host.openFirewall) { + allowedUDPPorts = [cfg.downstreams.host.port]; }) ]; }; diff --git a/modules/nixos-modules/server/crab-hole/impermanence.nix b/modules/nixos-modules/server/crab-hole/impermanence.nix index 455e593..51efc0c 100644 --- a/modules/nixos-modules/server/crab-hole/impermanence.nix +++ b/modules/nixos-modules/server/crab-hole/impermanence.nix @@ -5,7 +5,14 @@ }: let workingDirectory = "/var/lib/private/crab-hole"; in { - config = lib.mkIf (config.services.immich.enable && config.host.impermanence.enable) { + options.services.crab-hole = { + impermanence.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.crab-hole.enable && config.host.impermanence.enable; + }; + }; + + config = lib.mkIf config.services.crab-hole.impermanence.enable { assertions = [ { assertion = diff --git a/modules/nixos-modules/server/default.nix b/modules/nixos-modules/server/default.nix index 57874d5..2b33089 100644 --- a/modules/nixos-modules/server/default.nix +++ b/modules/nixos-modules/server/default.nix @@ -1,10 +1,9 @@ {...}: { imports = [ - ./reverse_proxy.nix - ./fail2ban.nix - ./postgres.nix + ./reverseProxy + ./fail2ban + ./postgres ./network_storage - ./podman.nix ./actual ./bazarr @@ -18,7 +17,7 @@ ./lidarr ./panoramax ./paperless - ./qbittorent.nix + ./qbittorent ./radarr ./searx ./sonarr diff --git a/modules/nixos-modules/server/fail2ban.nix b/modules/nixos-modules/server/fail2ban.nix deleted file mode 100644 index d19aeeb..0000000 --- a/modules/nixos-modules/server/fail2ban.nix +++ /dev/null @@ -1,74 +0,0 @@ -{ - lib, - pkgs, - config, - ... -}: let - dataFolder = "/var/lib/fail2ban"; - dataFile = "fail2ban.sqlite3"; -in { - config = lib.mkIf config.services.fail2ban.enable (lib.mkMerge [ - { - environment.etc = { - "fail2ban/filter.d/nginx.local".text = lib.mkIf config.services.nginx.enable ( - pkgs.lib.mkDefault (pkgs.lib.mkAfter '' - [Definition] - failregex = "limiting requests, excess:.* by zone.*client: " - '') - ); - }; - - services.fail2ban = { - maxretry = 5; - ignoreIP = [ - # Whitelist local networks - "10.0.0.0/8" - "172.16.0.0/12" - "192.168.0.0/16" - - # tail scale tailnet - "100.64.0.0/10" - "fd7a:115c:a1e0::/48" - ]; - bantime = "24h"; # Ban IPs for one day on the first ban - bantime-increment = { - enable = true; # Enable increment of bantime after each violation - formula = "ban.Time * math.exp(float(ban.Count+1)*banFactor)/math.exp(1*banFactor)"; - maxtime = "168h"; # Do not ban for more than 1 week - overalljails = true; # Calculate the ban time based on all the violations - }; - jails = { - nginx-iptables.settings = lib.mkIf config.services.nginx.enable { - enabled = true; - filter = "nginx"; - action = ''iptables-multiport[name=HTTP, port="http,https"]''; - backend = "auto"; - findtime = 600; - bantime = 600; - maxretry = 5; - }; - # TODO; figure out if there is any fail2ban things we can do on searx - # searx-iptables.settings = lib.mkIf config.services.searx.enable {}; - }; - }; - } - (lib.mkIf config.host.impermanence.enable { - assertions = [ - { - assertion = config.services.fail2ban.daemonSettings.Definition.dbfile == "${dataFolder}/${dataFile}"; - message = "fail2ban data file does not match persistence"; - } - ]; - - environment.persistence."/persist/system/root" = { - directories = [ - { - directory = dataFolder; - user = "fail2ban"; - group = "fail2ban"; - } - ]; - }; - }) - ]); -} diff --git a/modules/nixos-modules/server/fail2ban/default.nix b/modules/nixos-modules/server/fail2ban/default.nix new file mode 100644 index 0000000..30fca99 --- /dev/null +++ b/modules/nixos-modules/server/fail2ban/default.nix @@ -0,0 +1,6 @@ +{...}: { + imports = [ + ./fail2ban.nix + ./impermanence.nix + ]; +} diff --git a/modules/nixos-modules/server/fail2ban/fail2ban.nix b/modules/nixos-modules/server/fail2ban/fail2ban.nix new file mode 100644 index 0000000..261c68f --- /dev/null +++ b/modules/nixos-modules/server/fail2ban/fail2ban.nix @@ -0,0 +1,51 @@ +{ + lib, + pkgs, + config, + ... +}: { + config = lib.mkIf config.services.fail2ban.enable { + environment.etc = { + "fail2ban/filter.d/nginx.local".text = lib.mkIf config.services.nginx.enable ( + pkgs.lib.mkDefault (pkgs.lib.mkAfter '' + [Definition] + failregex = "limiting requests, excess:.* by zone.*client: " + '') + ); + }; + + services.fail2ban = { + maxretry = 5; + ignoreIP = [ + # Whitelist local networks + "10.0.0.0/8" + "172.16.0.0/12" + "192.168.0.0/16" + + # tail scale tailnet + "100.64.0.0/10" + "fd7a:115c:a1e0::/48" + ]; + bantime = "24h"; # Ban IPs for one day on the first ban + bantime-increment = { + enable = true; # Enable increment of bantime after each violation + formula = "ban.Time * math.exp(float(ban.Count+1)*banFactor)/math.exp(1*banFactor)"; + maxtime = "168h"; # Do not ban for more than 1 week + overalljails = true; # Calculate the ban time based on all the violations + }; + jails = { + nginx-iptables.settings = lib.mkIf config.services.nginx.enable { + enabled = true; + filter = "nginx"; + action = ''iptables-multiport[name=HTTP, port="http,https"]''; + backend = "auto"; + findtime = 600; + bantime = 600; + maxretry = 5; + }; + # TODO; figure out if there is any fail2ban things we can do on searx + # searx-iptables.settings = lib.mkIf config.services.searx.enable {}; + }; + }; + }; +} diff --git a/modules/nixos-modules/server/fail2ban/impermanence.nix b/modules/nixos-modules/server/fail2ban/impermanence.nix new file mode 100644 index 0000000..6e214b3 --- /dev/null +++ b/modules/nixos-modules/server/fail2ban/impermanence.nix @@ -0,0 +1,34 @@ +{ + lib, + config, + ... +}: let + dataFolder = "/var/lib/fail2ban"; + dataFile = "fail2ban.sqlite3"; +in { + options.services.fail2ban = { + impermanence.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.fail2ban.enable && config.host.impermanence.enable; + }; + }; + + config = lib.mkIf config.services.fail2ban.impermanence.enable { + assertions = [ + { + assertion = config.services.fail2ban.daemonSettings.Definition.dbfile == "${dataFolder}/${dataFile}"; + message = "fail2ban data file does not match persistence"; + } + ]; + + environment.persistence."/persist/system/root" = { + directories = [ + { + directory = dataFolder; + user = "fail2ban"; + group = "fail2ban"; + } + ]; + }; + }; +} diff --git a/modules/nixos-modules/server/flaresolverr/default.nix b/modules/nixos-modules/server/flaresolverr/default.nix index f39d940..86dbb4b 100644 --- a/modules/nixos-modules/server/flaresolverr/default.nix +++ b/modules/nixos-modules/server/flaresolverr/default.nix @@ -1,6 +1,5 @@ {...}: { imports = [ - ./proxy.nix ./impermanence.nix ]; } diff --git a/modules/nixos-modules/server/flaresolverr/impermanence.nix b/modules/nixos-modules/server/flaresolverr/impermanence.nix index b568a56..4544e75 100644 --- a/modules/nixos-modules/server/flaresolverr/impermanence.nix +++ b/modules/nixos-modules/server/flaresolverr/impermanence.nix @@ -3,7 +3,14 @@ config, ... }: { - config = lib.mkIf (config.services.flaresolverr.enable && config.host.impermanence.enable) { + options.services.flaresolverr = { + impermanence.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.flaresolverr.enable && config.host.impermanence.enable; + }; + }; + + config = lib.mkIf config.services.flaresolverr.impermanence.enable { # FlareSolverr typically doesn't need persistent storage as it's a proxy service # but we'll add basic structure in case it's needed for logs or configuration environment.persistence."/persist/system/root" = { diff --git a/modules/nixos-modules/server/flaresolverr/proxy.nix b/modules/nixos-modules/server/flaresolverr/proxy.nix deleted file mode 100644 index 5b8dd4c..0000000 --- a/modules/nixos-modules/server/flaresolverr/proxy.nix +++ /dev/null @@ -1,28 +0,0 @@ -{ - lib, - config, - ... -}: { - options.services.flaresolverr = { - subdomain = lib.mkOption { - type = lib.types.nullOr lib.types.str; - default = null; - description = "Subdomain for reverse proxy. If null, service will be local only."; - }; - extraSubdomains = lib.mkOption { - type = lib.types.listOf lib.types.str; - default = []; - description = "Extra subdomains for reverse proxy."; - }; - }; - - config = lib.mkIf (config.services.flaresolverr.enable && config.services.flaresolverr.subdomain != null) { - host.reverse_proxy.subdomains.flaresolverr = { - subdomain = config.services.flaresolverr.subdomain; - extraSubdomains = config.services.flaresolverr.extraSubdomains; - target = "http://127.0.0.1:${toString config.services.flaresolverr.port}"; - websockets.enable = true; - forwardHeaders.enable = true; - }; - }; -} diff --git a/modules/nixos-modules/server/forgejo/database.nix b/modules/nixos-modules/server/forgejo/database.nix index 0417aab..bb8781c 100644 --- a/modules/nixos-modules/server/forgejo/database.nix +++ b/modules/nixos-modules/server/forgejo/database.nix @@ -2,40 +2,31 @@ lib, config, ... -}: { - config = lib.mkIf config.services.forgejo.enable ( - lib.mkMerge [ +}: let + usingPostgres = config.services.forgejo.database.type == "postgres"; +in { + config = lib.mkIf config.services.forgejo.enable { + assertions = [ { - host = { - postgres = { - enable = true; - }; - }; - - assertions = [ - { - assertion = config.services.forgejo.settings.database.DB_TYPE == "postgres"; - message = "Forgejo database type must be postgres"; - } - ]; + assertion = !usingPostgres || config.services.postgresql.enable; + message = "PostgreSQL must be enabled when Forgejo database type is postgres"; } - (lib.mkIf config.host.postgres.enable { - host = { - postgres = { - extraUsers = { - forgejo = { - isClient = true; - createUser = true; - }; - }; - extraDatabases = { - forgejo = { - name = "forgejo"; - }; - }; - }; - }; - }) - ] - ); + { + assertion = !(usingPostgres && config.services.forgejo.database.createDatabase) || (builtins.any (db: db == "forgejo") config.services.postgresql.ensureDatabases); + message = "Forgejo built-in database creation failed - expected 'forgejo' in ensureDatabases but got: ${builtins.toString config.services.postgresql.ensureDatabases}"; + } + { + assertion = !(usingPostgres && config.services.forgejo.database.createDatabase) || (builtins.any (user: user.name == "forgejo") config.services.postgresql.ensureUsers); + message = "Forgejo built-in user creation failed - expected user 'forgejo' in ensureUsers but got: ${builtins.toString (builtins.map (u: u.name) config.services.postgresql.ensureUsers)}"; + } + ]; + + services.forgejo.database.createDatabase = lib.mkDefault usingPostgres; + + systemd.services.forgejo = lib.mkIf usingPostgres { + requires = [ + config.systemd.services.postgresql.name + ]; + }; + }; } diff --git a/modules/nixos-modules/server/forgejo/default.nix b/modules/nixos-modules/server/forgejo/default.nix index 1fdc8d9..4333f69 100644 --- a/modules/nixos-modules/server/forgejo/default.nix +++ b/modules/nixos-modules/server/forgejo/default.nix @@ -1,53 +1,9 @@ { - lib, - config, - ... -}: let - const = import ./const.nix; - httpPort = const.httpPort; - sshPort = const.sshPort; - db_user = "forgejo"; -in { imports = [ + ./forgejo.nix ./proxy.nix ./database.nix ./fail2ban.nix ./impermanence.nix ]; - - config = lib.mkIf config.services.forgejo.enable { - assertions = [ - { - assertion = config.services.forgejo.settings.server.BUILTIN_SSH_SERVER_USER == config.users.users.git.name; - message = "Forgejo BUILTIN_SSH_SERVER_USER hardcoded value does not match expected git user name"; - } - ]; - - services.forgejo = { - database = { - type = "postgres"; - socket = "/run/postgresql"; - }; - lfs.enable = true; - settings = { - server = { - DOMAIN = "${config.services.forgejo.subdomain}.${config.host.reverse_proxy.hostname}"; - HTTP_PORT = httpPort; - START_SSH_SERVER = true; - SSH_LISTEN_PORT = sshPort; - SSH_PORT = 22; - BUILTIN_SSH_SERVER_USER = "git"; - ROOT_URL = "https://git.jan-leila.com"; - }; - service = { - DISABLE_REGISTRATION = true; - }; - database = { - DB_TYPE = "postgres"; - NAME = db_user; - USER = db_user; - }; - }; - }; - }; } diff --git a/modules/nixos-modules/server/forgejo/fail2ban.nix b/modules/nixos-modules/server/forgejo/fail2ban.nix index 213c804..dfe221a 100644 --- a/modules/nixos-modules/server/forgejo/fail2ban.nix +++ b/modules/nixos-modules/server/forgejo/fail2ban.nix @@ -4,7 +4,16 @@ pkgs, ... }: { - config = lib.mkIf (config.services.forgejo.enable && config.services.fail2ban.enable) { + options.services.forgejo = { + fail2ban = { + enable = lib.mkOption { + type = lib.types.bool; + default = config.services.forgejo.enable && config.services.fail2ban.enable; + }; + }; + }; + + config = lib.mkIf config.services.forgejo.fail2ban.enable { environment.etc = { "fail2ban/filter.d/forgejo.local".text = lib.mkIf config.services.forgejo.enable ( pkgs.lib.mkDefault (pkgs.lib.mkAfter '' diff --git a/modules/nixos-modules/server/forgejo/forgejo.nix b/modules/nixos-modules/server/forgejo/forgejo.nix new file mode 100644 index 0000000..70d3087 --- /dev/null +++ b/modules/nixos-modules/server/forgejo/forgejo.nix @@ -0,0 +1,46 @@ +{ + lib, + config, + ... +}: let + const = import ./const.nix; + httpPort = const.httpPort; + sshPort = const.sshPort; + db_user = "forgejo"; +in { + config = lib.mkIf config.services.forgejo.enable { + assertions = [ + { + assertion = config.services.forgejo.settings.server.BUILTIN_SSH_SERVER_USER == config.users.users.git.name; + message = "Forgejo BUILTIN_SSH_SERVER_USER hardcoded value does not match expected git user name"; + } + ]; + + services.forgejo = { + database = { + type = "postgres"; + socket = "/run/postgresql"; + }; + lfs.enable = true; + settings = { + server = { + DOMAIN = config.services.forgejo.reverseProxy.domain; + HTTP_PORT = httpPort; + START_SSH_SERVER = true; + SSH_LISTEN_PORT = sshPort; + SSH_PORT = 22; + BUILTIN_SSH_SERVER_USER = "git"; + ROOT_URL = "https://git.jan-leila.com"; + }; + service = { + DISABLE_REGISTRATION = true; + }; + database = { + DB_TYPE = "postgres"; + NAME = db_user; + USER = db_user; + }; + }; + }; + }; +} diff --git a/modules/nixos-modules/server/forgejo/impermanence.nix b/modules/nixos-modules/server/forgejo/impermanence.nix index 04f21a5..6fe3de8 100644 --- a/modules/nixos-modules/server/forgejo/impermanence.nix +++ b/modules/nixos-modules/server/forgejo/impermanence.nix @@ -5,7 +5,14 @@ }: let stateDir = "/var/lib/forgejo"; in { - config = lib.mkIf (config.services.forgejo.enable && config.host.impermanence.enable) { + options.services.forgejo = { + impermanence.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.forgejo.enable && config.host.impermanence.enable; + }; + }; + + config = lib.mkIf config.services.forgejo.impermanence.enable { assertions = [ { assertion = config.services.forgejo.stateDir == stateDir; diff --git a/modules/nixos-modules/server/forgejo/proxy.nix b/modules/nixos-modules/server/forgejo/proxy.nix index 51f769d..c2d3131 100644 --- a/modules/nixos-modules/server/forgejo/proxy.nix +++ b/modules/nixos-modules/server/forgejo/proxy.nix @@ -7,16 +7,33 @@ httpPort = const.httpPort; in { options.services.forgejo = { - subdomain = lib.mkOption { - type = lib.types.str; - description = "subdomain of base domain that forgejo will be hosted at"; - default = "forgejo"; + reverseProxy = { + enable = lib.mkOption { + type = lib.types.bool; + default = config.services.forgejo.enable && config.services.reverseProxy.enable; + }; + domain = lib.mkOption { + type = lib.types.str; + description = "domain that forgejo will be hosted at"; + default = "git.jan-leila.com"; + }; + extraDomains = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "extra domains that should be configured for forgejo"; + default = []; + }; }; }; - config = lib.mkIf (config.services.forgejo.enable && config.host.reverse_proxy.enable) { - host.reverse_proxy.subdomains.${config.services.forgejo.subdomain} = { + config = lib.mkIf config.services.forgejo.reverseProxy.enable { + services.reverseProxy.services.forgejo = { target = "http://localhost:${toString httpPort}"; + domain = config.services.forgejo.reverseProxy.domain; + extraDomains = config.services.forgejo.reverseProxy.extraDomains; + + settings = { + forwardHeaders.enable = true; + }; }; networking.firewall.allowedTCPPorts = [ diff --git a/modules/nixos-modules/server/home-assistant/database.nix b/modules/nixos-modules/server/home-assistant/database.nix index 0ac8002..f1927ed 100644 --- a/modules/nixos-modules/server/home-assistant/database.nix +++ b/modules/nixos-modules/server/home-assistant/database.nix @@ -2,55 +2,52 @@ lib, config, ... -}: let - dbUser = "hass"; -in { - config = lib.mkIf config.services.home-assistant.enable ( - lib.mkMerge [ +}: { + options.services.home-assistant = { + postgres = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Use PostgreSQL instead of SQLite"; + }; + user = lib.mkOption { + type = lib.types.str; + default = "hass"; + description = "Database user name"; + }; + database = lib.mkOption { + type = lib.types.str; + default = "hass"; + description = "Database name"; + }; + }; + }; + + config = lib.mkIf config.services.home-assistant.enable { + assertions = [ { - host = { - postgres = { - enable = true; - }; - }; - - assertions = [ - { - assertion = config.services.home-assistant.database == "postgres"; - message = "Home Assistant database type must be postgres"; - } - ]; + assertion = !config.services.home-assistant.postgres.enable || config.services.postgresql.enable; + message = "PostgreSQL must be enabled when using postgres database for Home Assistant"; } - (lib.mkIf config.host.postgres.enable { - host = { - postgres = { - extraUsers = { - ${dbUser} = { - isClient = true; - createUser = true; - }; - }; - extraDatabases = { - ${dbUser} = { - name = dbUser; - }; - }; - }; - }; + ]; - services.home-assistant = { - extraPackages = python3Packages: - with python3Packages; [ - psycopg2 - ]; - }; + services.postgresql.databases.home-assistant = lib.mkIf config.services.home-assistant.postgres.enable { + enable = true; + user = config.services.home-assistant.postgres.user; + database = config.services.home-assistant.postgres.database; + }; - systemd.services.home-assistant = { - requires = [ - config.systemd.services.postgresql.name - ]; - }; - }) - ] - ); + services.home-assistant = lib.mkIf config.services.home-assistant.postgres.enable { + extraPackages = python3Packages: + with python3Packages; [ + psycopg2 + ]; + }; + + systemd.services.home-assistant = lib.mkIf config.services.home-assistant.postgres.enable { + requires = [ + config.systemd.services.postgresql.name + ]; + }; + }; } diff --git a/modules/nixos-modules/server/home-assistant/default.nix b/modules/nixos-modules/server/home-assistant/default.nix index 83d8ba7..b6f9356 100644 --- a/modules/nixos-modules/server/home-assistant/default.nix +++ b/modules/nixos-modules/server/home-assistant/default.nix @@ -1,112 +1,10 @@ { - lib, - config, - ... -}: { imports = [ + ./home-assistant.nix ./proxy.nix ./database.nix ./fail2ban.nix ./impermanence.nix ./extensions ]; - - options.services.home-assistant = { - database = lib.mkOption { - type = lib.types.enum [ - "builtin" - "postgres" - ]; - description = "what database do we want to use"; - default = "builtin"; - }; - - extensions = { - sonos = { - enable = lib.mkEnableOption "enable the sonos plugin"; - port = lib.mkOption { - type = lib.types.int; - default = 1400; - description = "what port to use for sonos discovery"; - }; - }; - jellyfin = { - enable = lib.mkEnableOption "enable the jellyfin plugin"; - }; - wyoming = { - enable = lib.mkEnableOption "enable wyoming"; - }; - }; - }; - - config = lib.mkIf config.services.home-assistant.enable (lib.mkMerge [ - { - services.home-assistant = { - configDir = "/var/lib/hass"; - extraComponents = [ - "default_config" - "esphome" - "met" - "radio_browser" - "isal" - "zha" - "webostv" - "tailscale" - "syncthing" - "analytics_insights" - "unifi" - "openweathermap" - "ollama" - "mobile_app" - "logbook" - "ssdp" - "usb" - "webhook" - "bluetooth" - "dhcp" - "energy" - "history" - "backup" - "assist_pipeline" - "conversation" - "sun" - "zeroconf" - "cpuspeed" - ]; - config = { - http = { - server_port = 8123; - use_x_forwarded_for = true; - trusted_proxies = ["127.0.0.1" "::1"]; - ip_ban_enabled = true; - login_attempts_threshold = 10; - }; - homeassistant = { - external_url = "https://${config.services.home-assistant.subdomain}.${config.host.reverse_proxy.hostname}"; - # internal_url = "http://192.168.1.2:8123"; - }; - recorder.db_url = "postgresql://@/${config.services.home-assistant.configDir}"; - "automation manual" = []; - "automation ui" = "!include automations.yaml"; - mobile_app = {}; - }; - extraPackages = python3Packages: - with python3Packages; [ - hassil - numpy - gtts - ]; - }; - - # TODO: configure /var/lib/hass/secrets.yaml via sops - - networking.firewall.allowedUDPPorts = [ - 1900 - ]; - - systemd.tmpfiles.rules = [ - "f ${config.services.home-assistant.configDir}/automations.yaml 0755 hass hass" - ]; - } - ]); } diff --git a/modules/nixos-modules/server/home-assistant/fail2ban.nix b/modules/nixos-modules/server/home-assistant/fail2ban.nix index 6ac5900..25194ef 100644 --- a/modules/nixos-modules/server/home-assistant/fail2ban.nix +++ b/modules/nixos-modules/server/home-assistant/fail2ban.nix @@ -3,36 +3,46 @@ pkgs, config, ... -}: -lib.mkIf (config.services.fail2ban.enable && config.services.home-assistant.enable) { - environment.etc = { - "fail2ban/filter.d/hass.local".text = ( - pkgs.lib.mkDefault (pkgs.lib.mkAfter '' - [INCLUDES] - before = common.conf - - [Definition] - failregex = ^%(__prefix_line)s.*Login attempt or request with invalid authentication from .*$ - - ignoreregex = - - [Init] - datepattern = ^%%Y-%%m-%%d %%H:%%M:%%S - '') - ); +}: { + options.services.home-assistant = { + fail2ban = { + enable = lib.mkOption { + type = lib.types.bool; + default = config.services.fail2ban.enable && config.services.home-assistant.enable; + }; + }; }; - services.fail2ban = { - jails = { - home-assistant-iptables.settings = { - enabled = true; - filter = "hass"; - action = ''iptables-multiport[name=HTTP, port="http,https"]''; - logpath = "${config.services.home-assistant.configDir}/*.log"; - backend = "auto"; - findtime = 600; - bantime = 600; - maxretry = 5; + config = lib.mkIf config.services.home-assistant.fail2ban.enable { + environment.etc = { + "fail2ban/filter.d/hass.local".text = ( + pkgs.lib.mkDefault (pkgs.lib.mkAfter '' + [INCLUDES] + before = common.conf + + [Definition] + failregex = ^%(__prefix_line)s.*Login attempt or request with invalid authentication from .*$ + + ignoreregex = + + [Init] + datepattern = ^%%Y-%%m-%%d %%H:%%M:%%S + '') + ); + }; + + services.fail2ban = { + jails = { + home-assistant-iptables.settings = { + enabled = true; + filter = "hass"; + action = ''iptables-multiport[name=HTTP, port="http,https"]''; + logpath = "${config.services.home-assistant.configDir}/*.log"; + backend = "auto"; + findtime = 600; + bantime = 600; + maxretry = 5; + }; }; }; }; diff --git a/modules/nixos-modules/server/home-assistant/home-assistant.nix b/modules/nixos-modules/server/home-assistant/home-assistant.nix new file mode 100644 index 0000000..fa58d5e --- /dev/null +++ b/modules/nixos-modules/server/home-assistant/home-assistant.nix @@ -0,0 +1,104 @@ +{ + lib, + config, + ... +}: { + options.services.home-assistant = { + database = lib.mkOption { + type = lib.types.enum [ + "builtin" + "postgres" + ]; + description = "what database do we want to use"; + default = "builtin"; + }; + + extensions = { + sonos = { + enable = lib.mkEnableOption "enable the sonos plugin"; + port = lib.mkOption { + type = lib.types.int; + default = 1400; + description = "what port to use for sonos discovery"; + }; + }; + jellyfin = { + enable = lib.mkEnableOption "enable the jellyfin plugin"; + }; + wyoming = { + enable = lib.mkEnableOption "enable wyoming"; + }; + }; + }; + + config = lib.mkIf config.services.home-assistant.enable (lib.mkMerge [ + { + services.home-assistant = { + configDir = "/var/lib/hass"; + extraComponents = [ + "default_config" + "esphome" + "met" + "radio_browser" + "isal" + "zha" + "webostv" + "tailscale" + "syncthing" + "analytics_insights" + "unifi" + "openweathermap" + "ollama" + "mobile_app" + "logbook" + "ssdp" + "usb" + "webhook" + "bluetooth" + "dhcp" + "energy" + "history" + "backup" + "assist_pipeline" + "conversation" + "sun" + "zeroconf" + "cpuspeed" + ]; + config = { + http = { + server_port = 8123; + use_x_forwarded_for = true; + trusted_proxies = ["127.0.0.1" "::1"]; + ip_ban_enabled = true; + login_attempts_threshold = 10; + }; + homeassistant = { + external_url = "https://${config.services.home-assistant.domain}"; + # internal_url = "http://192.168.1.2:8123"; + }; + recorder.db_url = "postgresql://@/${config.services.home-assistant.configDir}"; + "automation manual" = []; + "automation ui" = "!include automations.yaml"; + mobile_app = {}; + }; + extraPackages = python3Packages: + with python3Packages; [ + hassil + numpy + gtts + ]; + }; + + # TODO: configure /var/lib/hass/secrets.yaml via sops + + networking.firewall.allowedUDPPorts = [ + 1900 + ]; + + systemd.tmpfiles.rules = [ + "f ${config.services.home-assistant.configDir}/automations.yaml 0755 hass hass" + ]; + } + ]); +} diff --git a/modules/nixos-modules/server/home-assistant/proxy.nix b/modules/nixos-modules/server/home-assistant/proxy.nix index ba8f20d..b756459 100644 --- a/modules/nixos-modules/server/home-assistant/proxy.nix +++ b/modules/nixos-modules/server/home-assistant/proxy.nix @@ -4,29 +4,39 @@ ... }: { options.services.home-assistant = { - subdomain = lib.mkOption { + domain = lib.mkOption { type = lib.types.str; - description = "subdomain of base domain that home-assistant will be hosted at"; - default = "home-assistant"; + description = "domain that home-assistant will be hosted at"; + default = "home-assistant.arpa"; + }; + extraDomains = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "extra domains that should be configured for home-assistant"; + default = []; + }; + reverseProxy = { + enable = lib.mkOption { + type = lib.types.bool; + default = config.services.reverseProxy.enable && config.services.home-assistant.enable; + }; }; }; - config = lib.mkIf (config.host.reverse_proxy.enable && config.services.home-assistant.enable) { - host = { - reverse_proxy.subdomains.${config.services.home-assistant.subdomain} = { - target = "http://localhost:${toString config.services.home-assistant.config.http.server_port}"; + config = lib.mkIf config.services.home-assistant.reverseProxy.enable { + services.reverseProxy.services.home-assistant = { + target = "http://localhost:${toString config.services.home-assistant.config.http.server_port}"; + domain = config.services.home-assistant.domain; + extraDomains = config.services.home-assistant.extraDomains; - websockets.enable = true; + settings = { + proxyWebsockets.enable = true; forwardHeaders.enable = true; - extraConfig = '' - add_header Upgrade $http_upgrade; - add_header Connection \"upgrade\"; - - proxy_buffering off; - - proxy_read_timeout 90; - ''; + # Custom timeout settings + proxyHeaders = { + enable = true; + timeout = 90; + }; }; }; }; diff --git a/modules/nixos-modules/server/immich/database.nix b/modules/nixos-modules/server/immich/database.nix index 74b1aaa..52af51e 100644 --- a/modules/nixos-modules/server/immich/database.nix +++ b/modules/nixos-modules/server/immich/database.nix @@ -3,24 +3,28 @@ config, ... }: { - config = lib.mkIf config.services.immich.enable (lib.mkMerge [ - { - host = { - postgres = { - enable = true; - }; - }; - } - (lib.mkIf config.host.postgres.enable { - host = { - postgres = { - extraUsers = { - ${config.services.immich.database.user} = { - isClient = true; - }; - }; - }; - }; - }) - ]); + config = lib.mkIf config.services.immich.enable { + assertions = [ + { + assertion = !config.services.immich.database.enable || config.services.postgresql.enable; + message = "PostgreSQL must be enabled when using postgres database for Immich"; + } + { + assertion = !(config.services.immich.database.enable && config.services.immich.database.createDB) || (builtins.any (db: db == "immich") config.services.postgresql.ensureDatabases); + message = "Immich built-in database creation failed - expected 'immich' in ensureDatabases but got: ${builtins.toString config.services.postgresql.ensureDatabases}"; + } + { + assertion = !(config.services.immich.database.enable && config.services.immich.database.createDB) || (builtins.any (user: user.name == "immich") config.services.postgresql.ensureUsers); + message = "Immich built-in user creation failed - expected user 'immich' in ensureUsers but got: ${builtins.toString (builtins.map (u: u.name) config.services.postgresql.ensureUsers)}"; + } + ]; + + # Note: Immich has built-in database creation via services.immich.database.createDB we only add the systemd dependency + + systemd.services.immich-server = lib.mkIf config.services.immich.database.enable { + requires = [ + config.systemd.services.postgresql.name + ]; + }; + }; } diff --git a/modules/nixos-modules/server/immich/fail2ban.nix b/modules/nixos-modules/server/immich/fail2ban.nix index c9ec87b..21593e7 100644 --- a/modules/nixos-modules/server/immich/fail2ban.nix +++ b/modules/nixos-modules/server/immich/fail2ban.nix @@ -4,7 +4,16 @@ pkgs, ... }: { - config = lib.mkIf (config.services.fail2ban.enable && config.services.immich.enable) { + options.services.immich = { + fail2ban = { + enable = lib.mkOption { + type = lib.types.bool; + default = config.services.fail2ban.enable && config.services.immich.enable; + }; + }; + }; + + config = lib.mkIf config.services.immich.fail2ban.enable { environment.etc = { "fail2ban/filter.d/immich.local".text = pkgs.lib.mkDefault (pkgs.lib.mkAfter '' [Definition] diff --git a/modules/nixos-modules/server/immich/impermanence.nix b/modules/nixos-modules/server/immich/impermanence.nix index f63d178..56e51d0 100644 --- a/modules/nixos-modules/server/immich/impermanence.nix +++ b/modules/nixos-modules/server/immich/impermanence.nix @@ -5,7 +5,14 @@ }: let mediaLocation = "/var/lib/immich"; in { - config = lib.mkIf (config.services.immich.enable && config.host.impermanence.enable) { + options.services.immich = { + impermanence.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.immich.enable && config.host.impermanence.enable; + }; + }; + + config = lib.mkIf config.services.immich.impermanence.enable { assertions = [ { assertion = config.services.immich.mediaLocation == mediaLocation; diff --git a/modules/nixos-modules/server/immich/proxy.nix b/modules/nixos-modules/server/immich/proxy.nix index dae2420..9c8c165 100644 --- a/modules/nixos-modules/server/immich/proxy.nix +++ b/modules/nixos-modules/server/immich/proxy.nix @@ -4,31 +4,40 @@ ... }: { options.services.immich = { - subdomain = lib.mkOption { + domain = lib.mkOption { type = lib.types.str; - description = "subdomain of base domain that immich will be hosted at"; - default = "immich"; + description = "domain that immich will be hosted at"; + default = "immich.arpa"; + }; + extraDomains = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "extra domains that should be configured for immich"; + default = []; + }; + reverseProxy = { + enable = lib.mkOption { + type = lib.types.bool; + default = config.services.immich.enable && config.services.reverseProxy.enable; + }; }; }; - config = lib.mkIf (config.services.immich.enable && config.host.reverse_proxy.enable) { - host = { - reverse_proxy.subdomains.${config.services.immich.subdomain} = { - target = "http://localhost:${toString config.services.immich.port}"; + config = lib.mkIf config.services.immich.reverseProxy.enable { + services.reverseProxy.services.immich = { + target = "http://localhost:${toString config.services.immich.port}"; + domain = config.services.immich.domain; + extraDomains = config.services.immich.extraDomains; - websockets.enable = true; + settings = { + proxyWebsockets.enable = true; forwardHeaders.enable = true; + maxBodySize = 50000; - extraConfig = '' - # allow large file uploads - client_max_body_size 50000M; - - # set timeout - proxy_read_timeout 600s; - proxy_send_timeout 600s; - send_timeout 600s; - proxy_redirect off; - ''; + # Custom timeout settings + proxyHeaders = { + enable = true; + timeout = 600; + }; }; }; }; diff --git a/modules/nixos-modules/server/jackett/default.nix b/modules/nixos-modules/server/jackett/default.nix index f39d940..86dbb4b 100644 --- a/modules/nixos-modules/server/jackett/default.nix +++ b/modules/nixos-modules/server/jackett/default.nix @@ -1,6 +1,5 @@ {...}: { imports = [ - ./proxy.nix ./impermanence.nix ]; } diff --git a/modules/nixos-modules/server/jackett/impermanence.nix b/modules/nixos-modules/server/jackett/impermanence.nix index 5826a54..24fc5e6 100644 --- a/modules/nixos-modules/server/jackett/impermanence.nix +++ b/modules/nixos-modules/server/jackett/impermanence.nix @@ -5,7 +5,14 @@ }: let jackett_data_directory = "/var/lib/jackett/.config/Jackett"; in { - config = lib.mkIf (config.services.jackett.enable && config.host.impermanence.enable) { + options.services.jackett = { + impermanence.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.jackett.enable && config.host.impermanence.enable; + }; + }; + + config = lib.mkIf config.services.jackett.impermanence.enable { assertions = [ { assertion = config.services.jackett.dataDir == jackett_data_directory; diff --git a/modules/nixos-modules/server/jackett/proxy.nix b/modules/nixos-modules/server/jackett/proxy.nix deleted file mode 100644 index af5fa79..0000000 --- a/modules/nixos-modules/server/jackett/proxy.nix +++ /dev/null @@ -1,28 +0,0 @@ -{ - lib, - config, - ... -}: { - options.services.jackett = { - subdomain = lib.mkOption { - type = lib.types.nullOr lib.types.str; - default = null; - description = "Subdomain for reverse proxy. If null, service will be local only."; - }; - extraSubdomains = lib.mkOption { - type = lib.types.listOf lib.types.str; - default = []; - description = "Extra subdomains for reverse proxy."; - }; - }; - - config = lib.mkIf (config.services.jackett.enable && config.services.jackett.subdomain != null) { - host.reverse_proxy.subdomains.jackett = { - subdomain = config.services.jackett.subdomain; - extraSubdomains = config.services.jackett.extraSubdomains; - target = "http://127.0.0.1:9117"; - websockets.enable = true; - forwardHeaders.enable = true; - }; - }; -} diff --git a/modules/nixos-modules/server/jellyfin/default.nix b/modules/nixos-modules/server/jellyfin/default.nix index 0d88481..2dbdcfd 100644 --- a/modules/nixos-modules/server/jellyfin/default.nix +++ b/modules/nixos-modules/server/jellyfin/default.nix @@ -1,38 +1,8 @@ { - lib, - pkgs, - config, - ... -}: let - jellyfinPort = 8096; - dlanPort = 1900; -in { imports = [ + ./jellyfin.nix ./proxy.nix ./fail2ban.nix ./impermanence.nix ]; - - options.services.jellyfin = { - media_directory = lib.mkOption { - type = lib.types.str; - description = "directory jellyfin media will be hosted at"; - default = "/srv/jellyfin/media"; - }; - }; - - config = lib.mkIf config.services.jellyfin.enable { - environment.systemPackages = [ - pkgs.jellyfin - pkgs.jellyfin-web - pkgs.jellyfin-ffmpeg - ]; - - networking.firewall.allowedTCPPorts = [jellyfinPort dlanPort]; - - systemd.tmpfiles.rules = [ - "d ${config.services.jellyfin.media_directory} 2770 jellyfin jellyfin_media" - "A ${config.services.jellyfin.media_directory} - - - - u:jellyfin:rwX,g:jellyfin_media:rwX,o::-" - ]; - }; } diff --git a/modules/nixos-modules/server/jellyfin/impermanence.nix b/modules/nixos-modules/server/jellyfin/impermanence.nix index e0b3b5d..cbcb54f 100644 --- a/modules/nixos-modules/server/jellyfin/impermanence.nix +++ b/modules/nixos-modules/server/jellyfin/impermanence.nix @@ -6,7 +6,14 @@ jellyfin_data_directory = "/var/lib/jellyfin"; jellyfin_cache_directory = "/var/cache/jellyfin"; in { - config = lib.mkIf (config.services.jellyfin.enable && config.host.impermanence.enable) { + options.services.jellyfin = { + impermanence.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.jellyfin.enable && config.host.impermanence.enable; + }; + }; + + config = lib.mkIf config.services.jellyfin.impermanence.enable { fileSystems."/persist/system/jellyfin".neededForBoot = true; host.storage.pool.extraDatasets = { diff --git a/modules/nixos-modules/server/jellyfin/jellyfin.nix b/modules/nixos-modules/server/jellyfin/jellyfin.nix new file mode 100644 index 0000000..9bfa921 --- /dev/null +++ b/modules/nixos-modules/server/jellyfin/jellyfin.nix @@ -0,0 +1,32 @@ +{ + lib, + pkgs, + config, + ... +}: let + jellyfinPort = 8096; + dlanPort = 1900; +in { + options.services.jellyfin = { + media_directory = lib.mkOption { + type = lib.types.str; + description = "directory jellyfin media will be hosted at"; + default = "/srv/jellyfin/media"; + }; + }; + + config = lib.mkIf config.services.jellyfin.enable { + environment.systemPackages = [ + pkgs.jellyfin + pkgs.jellyfin-web + pkgs.jellyfin-ffmpeg + ]; + + networking.firewall.allowedTCPPorts = [jellyfinPort dlanPort]; + + systemd.tmpfiles.rules = [ + "d ${config.services.jellyfin.media_directory} 2770 jellyfin jellyfin_media" + "A ${config.services.jellyfin.media_directory} - - - - u:jellyfin:rwX,g:jellyfin_media:rwX,o::-" + ]; + }; +} diff --git a/modules/nixos-modules/server/jellyfin/proxy.nix b/modules/nixos-modules/server/jellyfin/proxy.nix index 1020a19..35289e7 100644 --- a/modules/nixos-modules/server/jellyfin/proxy.nix +++ b/modules/nixos-modules/server/jellyfin/proxy.nix @@ -6,33 +6,36 @@ jellyfinPort = 8096; in { options.services.jellyfin = { - subdomain = lib.mkOption { + domain = lib.mkOption { type = lib.types.str; - description = "subdomain of base domain that jellyfin will be hosted at"; - default = "jellyfin"; + description = "domain that jellyfin will be hosted at"; + default = "jellyfin.arpa"; }; - extraSubdomains = lib.mkOption { + extraDomains = lib.mkOption { type = lib.types.listOf lib.types.str; - description = "ex subdomain of base domain that jellyfin will be hosted at"; + description = "extra domains that should be configured for jellyfin"; default = []; }; + reverseProxy = { + enable = lib.mkOption { + type = lib.types.bool; + default = config.services.jellyfin.enable && config.services.reverseProxy.enable; + }; + }; }; - config = lib.mkIf (config.services.jellyfin.enable && config.host.reverse_proxy.enable) { - host.reverse_proxy.subdomains.jellyfin = { + config = lib.mkIf config.services.jellyfin.reverseProxy.enable { + services.reverseProxy.services.jellyfin = { target = "http://localhost:${toString jellyfinPort}"; + domain = config.services.jellyfin.domain; + extraDomains = config.services.jellyfin.extraDomains; - subdomain = config.services.jellyfin.subdomain; - extraSubdomains = config.services.jellyfin.extraSubdomains; - - forwardHeaders.enable = true; - - extraConfig = '' - client_max_body_size 20M; - add_header X-Content-Type-Options "nosniff"; - - proxy_buffering off; - ''; + settings = { + forwardHeaders.enable = true; + maxBodySize = 20; + noSniff.enable = true; + proxyBuffering.enable = false; + }; }; }; } diff --git a/modules/nixos-modules/server/lidarr/default.nix b/modules/nixos-modules/server/lidarr/default.nix index f39d940..86dbb4b 100644 --- a/modules/nixos-modules/server/lidarr/default.nix +++ b/modules/nixos-modules/server/lidarr/default.nix @@ -1,6 +1,5 @@ {...}: { imports = [ - ./proxy.nix ./impermanence.nix ]; } diff --git a/modules/nixos-modules/server/lidarr/impermanence.nix b/modules/nixos-modules/server/lidarr/impermanence.nix index 689b924..5d3aa3f 100644 --- a/modules/nixos-modules/server/lidarr/impermanence.nix +++ b/modules/nixos-modules/server/lidarr/impermanence.nix @@ -5,7 +5,14 @@ }: let lidarr_data_directory = "/var/lib/lidarr/.config/Lidarr"; in { - config = lib.mkIf (config.services.lidarr.enable && config.host.impermanence.enable) { + options.services.lidarr = { + impermanence.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.lidarr.enable && config.host.impermanence.enable; + }; + }; + + config = lib.mkIf config.services.lidarr.impermanence.enable { assertions = [ { assertion = config.services.lidarr.dataDir == lidarr_data_directory; diff --git a/modules/nixos-modules/server/lidarr/proxy.nix b/modules/nixos-modules/server/lidarr/proxy.nix deleted file mode 100644 index 0146ccf..0000000 --- a/modules/nixos-modules/server/lidarr/proxy.nix +++ /dev/null @@ -1,28 +0,0 @@ -{ - lib, - config, - ... -}: { - options.services.lidarr = { - subdomain = lib.mkOption { - type = lib.types.nullOr lib.types.str; - default = null; - description = "Subdomain for reverse proxy. If null, service will be local only."; - }; - extraSubdomains = lib.mkOption { - type = lib.types.listOf lib.types.str; - default = []; - description = "Extra subdomains for reverse proxy."; - }; - }; - - config = lib.mkIf (config.services.lidarr.enable && config.services.lidarr.subdomain != null) { - host.reverse_proxy.subdomains.lidarr = { - subdomain = config.services.lidarr.subdomain; - extraSubdomains = config.services.lidarr.extraSubdomains; - target = "http://127.0.0.1:8686"; - websockets.enable = true; - forwardHeaders.enable = true; - }; - }; -} diff --git a/modules/nixos-modules/server/network_storage/default.nix b/modules/nixos-modules/server/network_storage/default.nix index eaac7fe..cd100ab 100644 --- a/modules/nixos-modules/server/network_storage/default.nix +++ b/modules/nixos-modules/server/network_storage/default.nix @@ -1,90 +1,6 @@ { - config, - lib, - ... -}: let - export_directory = config.host.network_storage.export_directory; -in { imports = [ + ./network_storage.nix ./nfs.nix ]; - - options = { - host.network_storage = { - enable = lib.mkEnableOption "is this machine going to export network storage"; - export_directory = lib.mkOption { - type = lib.types.path; - description = "what are exports going to be stored in"; - default = "/exports"; - }; - directories = lib.mkOption { - type = lib.types.listOf (lib.types.submodule ({config, ...}: { - options = { - folder = lib.mkOption { - type = lib.types.str; - description = "what is the name of this export directory"; - }; - bind = lib.mkOption { - type = lib.types.nullOr lib.types.path; - description = "is this directory bound to anywhere"; - default = null; - }; - user = lib.mkOption { - type = lib.types.str; - description = "what user owns this directory"; - default = "nouser"; - }; - group = lib.mkOption { - type = lib.types.str; - description = "what group owns this directory"; - default = "nogroup"; - }; - _directory = lib.mkOption { - internal = true; - readOnly = true; - type = lib.types.path; - default = "${export_directory}/${config.folder}"; - }; - }; - })); - description = "list of directory names to export"; - }; - }; - }; - - config = lib.mkIf config.host.network_storage.enable (lib.mkMerge [ - { - # create any folders that we need to have for our exports - systemd.tmpfiles.rules = - [ - "d ${config.host.network_storage.export_directory} 2775 nobody nogroup -" - ] - ++ ( - builtins.map ( - directory: "d ${directory._directory} 2770 ${directory.user} ${directory.group}" - ) - config.host.network_storage.directories - ); - - # set up any bind mounts that we need for our exports - fileSystems = builtins.listToAttrs ( - builtins.map (directory: - lib.attrsets.nameValuePair directory._directory { - device = directory.bind; - options = ["bind"]; - }) ( - builtins.filter (directory: directory.bind != null) config.host.network_storage.directories - ) - ); - } - # (lib.mkIf config.host.impermanence.enable { - # environment.persistence."/persist/system/root" = { - # enable = true; - # hideMounts = true; - # directories = [ - # config.host.network_storage.export_directory - # ]; - # }; - # }) - ]); } diff --git a/modules/nixos-modules/server/network_storage/network_storage.nix b/modules/nixos-modules/server/network_storage/network_storage.nix new file mode 100644 index 0000000..ebc3bee --- /dev/null +++ b/modules/nixos-modules/server/network_storage/network_storage.nix @@ -0,0 +1,86 @@ +{ + config, + lib, + ... +}: let + export_directory = config.host.network_storage.export_directory; +in { + options = { + host.network_storage = { + enable = lib.mkEnableOption "is this machine going to export network storage"; + export_directory = lib.mkOption { + type = lib.types.path; + description = "what are exports going to be stored in"; + default = "/exports"; + }; + directories = lib.mkOption { + type = lib.types.listOf (lib.types.submodule ({config, ...}: { + options = { + folder = lib.mkOption { + type = lib.types.str; + description = "what is the name of this export directory"; + }; + bind = lib.mkOption { + type = lib.types.nullOr lib.types.path; + description = "is this directory bound to anywhere"; + default = null; + }; + user = lib.mkOption { + type = lib.types.str; + description = "what user owns this directory"; + default = "nouser"; + }; + group = lib.mkOption { + type = lib.types.str; + description = "what group owns this directory"; + default = "nogroup"; + }; + _directory = lib.mkOption { + internal = true; + readOnly = true; + type = lib.types.path; + default = "${export_directory}/${config.folder}"; + }; + }; + })); + description = "list of directory names to export"; + }; + }; + }; + + config = lib.mkIf config.host.network_storage.enable (lib.mkMerge [ + { + # create any folders that we need to have for our exports + systemd.tmpfiles.rules = + [ + "d ${config.host.network_storage.export_directory} 2775 nobody nogroup -" + ] + ++ ( + builtins.map ( + directory: "d ${directory._directory} 2770 ${directory.user} ${directory.group}" + ) + config.host.network_storage.directories + ); + + # set up any bind mounts that we need for our exports + fileSystems = builtins.listToAttrs ( + builtins.map (directory: + lib.attrsets.nameValuePair directory._directory { + device = directory.bind; + options = ["bind"]; + }) ( + builtins.filter (directory: directory.bind != null) config.host.network_storage.directories + ) + ); + } + # (lib.mkIf config.host.impermanence.enable { + # environment.persistence."/persist/system/root" = { + # enable = true; + # hideMounts = true; + # directories = [ + # config.host.network_storage.export_directory + # ]; + # }; + # }) + ]); +} diff --git a/modules/nixos-modules/server/panoramax/database.nix b/modules/nixos-modules/server/panoramax/database.nix index 8679f9a..1721726 100644 --- a/modules/nixos-modules/server/panoramax/database.nix +++ b/modules/nixos-modules/server/panoramax/database.nix @@ -3,32 +3,46 @@ config, ... }: { - config = lib.mkIf config.services.panoramax.enable (lib.mkMerge [ - { - host = { - postgres = { - enable = true; + options.services.panoramax = { + database = { + postgres = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Use PostgreSQL instead of SQLite"; + }; + user = lib.mkOption { + type = lib.types.str; + default = "panoramax"; + description = "Database user name"; + }; + database = lib.mkOption { + type = lib.types.str; + default = "panoramax"; + description = "Database name"; }; }; - } - ( - lib.mkIf config.host.postgres.enable { - host = { - postgres = { - extraUsers = { - ${config.services.panoramax.database.user} = { - isClient = true; - createUser = true; - }; - }; - extraDatabases = { - ${config.services.panoramax.database.name} = { - name = config.services.panoramax.database.user; - }; - }; - }; - }; + }; + }; + + config = lib.mkIf config.services.panoramax.enable { + assertions = [ + { + assertion = !config.services.panoramax.database.postgres.enable || config.services.postgresql.enable; + message = "PostgreSQL must be enabled when using postgres database for Panoramax"; } - ) - ]); + ]; + + services.postgresql.databases.panoramax = lib.mkIf config.services.panoramax.database.postgres.enable { + enable = true; + user = config.services.panoramax.database.postgres.user; + database = config.services.panoramax.database.postgres.database; + }; + + systemd.services.panoramax = lib.mkIf config.services.panoramax.database.postgres.enable { + requires = [ + config.systemd.services.postgresql.name + ]; + }; + }; } diff --git a/modules/nixos-modules/server/panoramax/impermanence.nix b/modules/nixos-modules/server/panoramax/impermanence.nix index 41b1401..e25ef92 100644 --- a/modules/nixos-modules/server/panoramax/impermanence.nix +++ b/modules/nixos-modules/server/panoramax/impermanence.nix @@ -3,7 +3,14 @@ config, ... }: { - config = lib.mkIf (config.services.panoramax.enable && config.host.impermanence.enable) { + options.services.panoramax = { + impermanence.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.panoramax.enable && config.host.impermanence.enable; + }; + }; + + config = lib.mkIf config.services.panoramax.impermanence.enable { # TODO: configure impermanence for panoramax data # This would typically include directories like: # - /var/lib/panoramax diff --git a/modules/nixos-modules/server/panoramax/proxy.nix b/modules/nixos-modules/server/panoramax/proxy.nix index 79f9326..7cd7111 100644 --- a/modules/nixos-modules/server/panoramax/proxy.nix +++ b/modules/nixos-modules/server/panoramax/proxy.nix @@ -4,31 +4,35 @@ ... }: { options.services.panoramax = { - subdomain = lib.mkOption { + domain = lib.mkOption { type = lib.types.str; - description = "subdomain of base domain that panoramax will be hosted at"; - default = "panoramax"; + description = "domain that panoramax will be hosted at"; + default = "panoramax.arpa"; + }; + extraDomains = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "extra domains that should be configured for panoramax"; + default = []; + }; + reverseProxy = { + enable = lib.mkOption { + type = lib.types.bool; + default = config.services.panoramax.enable && config.services.reverseProxy.enable; + }; }; }; - config = lib.mkIf (config.services.panoramax.enable && config.host.reverse_proxy.enable) { - host = { - reverse_proxy.subdomains.${config.services.panoramax.subdomain} = { - target = "http://localhost:${toString config.services.panoramax.port}"; + config = lib.mkIf config.services.panoramax.reverseProxy.enable { + services.reverseProxy.services.panoramax = { + target = "http://localhost:${toString config.services.panoramax.port}"; + domain = config.services.panoramax.domain; + extraDomains = config.services.panoramax.extraDomains; - websockets.enable = true; + settings = { + proxyWebsockets.enable = true; forwardHeaders.enable = true; - - extraConfig = '' - # allow large file uploads for panoramic images - client_max_body_size 100M; - - # set timeout for image processing - proxy_read_timeout 300s; - proxy_send_timeout 300s; - send_timeout 300s; - proxy_redirect off; - ''; + maxBodySize = 100000; + timeout = 300; }; }; }; diff --git a/modules/nixos-modules/server/paperless/database.nix b/modules/nixos-modules/server/paperless/database.nix index 6f4ce51..c63e59d 100644 --- a/modules/nixos-modules/server/paperless/database.nix +++ b/modules/nixos-modules/server/paperless/database.nix @@ -3,32 +3,28 @@ lib, ... }: { - config = lib.mkIf config.services.paperless.enable (lib.mkMerge [ - { - host = { - postgres = { - enable = true; - }; - }; - } - ( - lib.mkIf config.host.postgres.enable { - host = { - postgres = { - extraUsers = { - ${config.services.paperless.database.user} = { - isClient = true; - createUser = true; - }; - }; - extraDatabases = { - ${config.services.paperless.database.user} = { - name = config.services.paperless.database.user; - }; - }; - }; - }; + config = lib.mkIf config.services.paperless.enable { + assertions = [ + { + assertion = !config.services.paperless.database.createLocally || config.services.postgresql.enable; + message = "PostgreSQL must be enabled when using local postgres database for Paperless"; } - ) - ]); + { + assertion = !config.services.paperless.database.createLocally || (builtins.any (db: db == "paperless") config.services.postgresql.ensureDatabases); + message = "Paperless built-in database creation failed - expected 'paperless' in ensureDatabases but got: ${builtins.toString config.services.postgresql.ensureDatabases}"; + } + { + assertion = !config.services.paperless.database.createLocally || (builtins.any (user: user.name == "paperless") config.services.postgresql.ensureUsers); + message = "Paperless built-in user creation failed - expected user 'paperless' in ensureUsers but got: ${builtins.toString (builtins.map (u: u.name) config.services.postgresql.ensureUsers)}"; + } + ]; + + services.paperless.database.createLocally = lib.mkDefault true; + + systemd.services.paperless-scheduler = lib.mkIf config.services.paperless.database.createLocally { + requires = [ + config.systemd.services.postgresql.name + ]; + }; + }; } diff --git a/modules/nixos-modules/server/paperless/default.nix b/modules/nixos-modules/server/paperless/default.nix index a6878eb..7e5e16b 100644 --- a/modules/nixos-modules/server/paperless/default.nix +++ b/modules/nixos-modules/server/paperless/default.nix @@ -1,35 +1,9 @@ { - config, - lib, - ... -}: { imports = [ + ./paperless.nix ./proxy.nix ./database.nix ./fail2ban.nix ./impermanence.nix ]; - - options.services.paperless = { - database = { - user = lib.mkOption { - type = lib.types.str; - description = "what is the user and database that we are going to use for paperless"; - default = "paperless"; - }; - }; - }; - - config = lib.mkIf config.services.paperless.enable { - services.paperless = { - domain = "${config.services.paperless.subdomain}.${config.host.reverse_proxy.hostname}"; - configureTika = true; - settings = { - PAPERLESS_DBENGINE = "postgresql"; - PAPERLESS_DBHOST = "/run/postgresql"; - PAPERLESS_DBNAME = config.services.paperless.database.user; - PAPERLESS_DBUSER = config.services.paperless.database.user; - }; - }; - }; } diff --git a/modules/nixos-modules/server/paperless/impermanence.nix b/modules/nixos-modules/server/paperless/impermanence.nix index d9e17bd..fc87ea7 100644 --- a/modules/nixos-modules/server/paperless/impermanence.nix +++ b/modules/nixos-modules/server/paperless/impermanence.nix @@ -5,7 +5,14 @@ }: let dataDir = "/var/lib/paperless"; in { - config = lib.mkIf (config.services.paperless.enable && config.host.impermanence.enable) { + options.services.paperless = { + impermanence.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.paperless.enable && config.host.impermanence.enable; + }; + }; + + config = lib.mkIf config.services.paperless.impermanence.enable { assertions = [ { assertion = config.services.paperless.dataDir == dataDir; diff --git a/modules/nixos-modules/server/paperless/paperless.nix b/modules/nixos-modules/server/paperless/paperless.nix new file mode 100644 index 0000000..5bcbfed --- /dev/null +++ b/modules/nixos-modules/server/paperless/paperless.nix @@ -0,0 +1,27 @@ +{ + config, + lib, + ... +}: { + options.services.paperless = { + database = { + user = lib.mkOption { + type = lib.types.str; + description = "what is the user and database that we are going to use for paperless"; + default = "paperless"; + }; + }; + }; + + config = lib.mkIf config.services.paperless.enable { + services.paperless = { + configureTika = true; + settings = { + PAPERLESS_DBENGINE = "postgresql"; + PAPERLESS_DBHOST = "/run/postgresql"; + PAPERLESS_DBNAME = config.services.paperless.database.user; + PAPERLESS_DBUSER = config.services.paperless.database.user; + }; + }; + }; +} diff --git a/modules/nixos-modules/server/paperless/proxy.nix b/modules/nixos-modules/server/paperless/proxy.nix index 2910f07..9d152c9 100644 --- a/modules/nixos-modules/server/paperless/proxy.nix +++ b/modules/nixos-modules/server/paperless/proxy.nix @@ -4,25 +4,29 @@ ... }: { options.services.paperless = { - subdomain = lib.mkOption { - type = lib.types.str; - description = "subdomain of base domain that paperless will be hosted at"; - default = "paperless"; + extraDomains = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "extra domains that should be configured for paperless"; + default = []; + }; + reverseProxy = { + enable = lib.mkOption { + type = lib.types.bool; + default = config.services.paperless.enable && config.services.reverseProxy.enable; + }; }; }; - config = lib.mkIf (config.services.paperless.enable && config.host.reverse_proxy.enable) { - host = { - reverse_proxy.subdomains.${config.services.paperless.subdomain} = { - target = "http://${config.services.paperless.address}:${toString config.services.paperless.port}"; + config = lib.mkIf config.services.paperless.reverseProxy.enable { + services.reverseProxy.services.paperless = { + target = "http://${config.services.paperless.address}:${toString config.services.paperless.port}"; + domain = config.services.paperless.domain; + extraDomains = config.services.paperless.extraDomains; - websockets.enable = true; + settings = { + proxyWebsockets.enable = true; forwardHeaders.enable = true; - - extraConfig = '' - # allow large file uploads - client_max_body_size 50000M; - ''; + maxBodySize = 50000; }; }; }; diff --git a/modules/nixos-modules/server/podman.nix b/modules/nixos-modules/server/podman.nix deleted file mode 100644 index 9301140..0000000 --- a/modules/nixos-modules/server/podman.nix +++ /dev/null @@ -1,73 +0,0 @@ -{ - lib, - config, - ... -}: { - options.host.podman = { - enable = lib.mkEnableOption "should podman be enabled on this computer"; - macvlan = { - subnet = lib.mkOption { - type = lib.types.str; - description = "Subnet for macvlan address range"; - }; - gateway = lib.mkOption { - type = lib.types.str; - description = "Gateway for macvlan"; - # TODO: see if we can default this to systemd network gateway - }; - networkInterface = lib.mkOption { - type = lib.types.str; - description = "Parent network interface for macvlan"; - # TODO: see if we can default this some interface? - }; - }; - }; - config = lib.mkIf config.host.podman.enable { - systemd = { - services = { - # "podman-network-macvlan" = { - # path = [pkgs.podman]; - # serviceConfig = { - # Type = "oneshot"; - # RemainAfterExit = true; - # ExecStop = "podman network rm -f macvlan"; - # }; - # script = '' - # podman network inspect macvlan || podman network create --driver macvlan --subnet ${config.host.podman.macvlan.subnet} --gateway ${config.host.podman.macvlan.gateway} --opt parent=${config.host.podman.macvlan.networkInterface} macvlan - # ''; - # partOf = ["podman-compose-root.target"]; - # wantedBy = ["podman-compose-root.target"]; - # }; - }; - # disable computer sleeping - targets = { - # Root service - # When started, this will automatically create all resources and start - # the containers. When stopped, this will teardown all resources. - "podman-compose-root" = { - unitConfig = { - Description = "Root target for podman targets."; - }; - wantedBy = ["multi-user.target"]; - }; - }; - }; - - virtualisation = { - # Runtime - podman = { - enable = true; - autoPrune.enable = true; - dockerCompat = true; - # defaultNetwork.settings = { - # # Required for container networking to be able to use names. - # dns_enabled = true; - # }; - }; - - oci-containers = { - backend = "podman"; - }; - }; - }; -} diff --git a/modules/nixos-modules/server/postgres.nix b/modules/nixos-modules/server/postgres.nix deleted file mode 100644 index 71ce44c..0000000 --- a/modules/nixos-modules/server/postgres.nix +++ /dev/null @@ -1,121 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: let - dataDir = "/var/lib/postgresql/16"; - adminUsers = lib.lists.filter (user: user.isAdmin) (lib.attrsets.mapAttrsToList (_: user: user) config.host.postgres.extraUsers); - clientUsers = lib.lists.filter (user: user.isClient) (lib.attrsets.mapAttrsToList (_: user: user) config.host.postgres.extraUsers); - createUsers = lib.lists.filter (user: user.createUser) (lib.attrsets.mapAttrsToList (_: user: user) config.host.postgres.extraUsers); - createDatabases = lib.attrsets.mapAttrsToList (_: user: user) config.host.postgres.extraDatabases; -in { - options = { - host.postgres = { - enable = lib.mkEnableOption "enable postgres"; - extraUsers = lib.mkOption { - type = lib.types.attrsOf (lib.types.submodule ({name, ...}: { - options = { - name = lib.mkOption { - type = lib.types.str; - default = name; - }; - isAdmin = lib.mkOption { - type = lib.types.bool; - default = false; - }; - isClient = lib.mkOption { - type = lib.types.bool; - default = false; - }; - createUser = lib.mkOption { - type = lib.types.bool; - default = false; - }; - }; - })); - default = {}; - }; - extraDatabases = lib.mkOption { - type = lib.types.attrsOf (lib.types.submodule ({name, ...}: { - options = { - name = lib.mkOption { - type = lib.types.str; - default = name; - }; - }; - })); - default = {}; - }; - }; - }; - - config = lib.mkIf config.host.postgres.enable (lib.mkMerge [ - { - services = { - postgresql = { - enable = true; - package = pkgs.postgresql_16; - ensureUsers = - [ - { - name = "postgres"; - } - ] - ++ ( - builtins.map (user: { - name = user.name; - ensureDBOwnership = true; - }) - createUsers - ); - ensureDatabases = builtins.map (database: database.name) createDatabases; - identMap = - '' - # ArbitraryMapName systemUser DBUser - - # Administration Users - superuser_map root postgres - superuser_map postgres postgres - '' - + ( - lib.strings.concatLines (builtins.map (user: "superuser_map ${user.name} postgres") adminUsers) - ) - + '' - - # Client Users - '' - + ( - lib.strings.concatLines (builtins.map (user: "user_map ${user.name} ${user.name}") clientUsers) - ); - # configuration here lets users access the db that matches their name and lets user postgres access everything - authentication = pkgs.lib.mkOverride 10 '' - # type database DBuser origin-address auth-method optional_ident_map - local all postgres peer map=superuser_map - local sameuser all peer map=user_map - ''; - }; - }; - } - - (lib.mkIf config.host.impermanence.enable { - assertions = [ - { - assertion = config.services.postgresql.dataDir == dataDir; - message = "postgres data directory does not match persistence"; - } - ]; - environment.persistence."/persist/system/root" = { - enable = true; - hideMounts = true; - directories = [ - { - directory = dataDir; - user = "postgres"; - group = "postgres"; - } - ]; - }; - }) - ]); -} diff --git a/modules/nixos-modules/server/postgres/default.nix b/modules/nixos-modules/server/postgres/default.nix new file mode 100644 index 0000000..abf4ade --- /dev/null +++ b/modules/nixos-modules/server/postgres/default.nix @@ -0,0 +1,6 @@ +{...}: { + imports = [ + ./postgres.nix + ./impermanence.nix + ]; +} diff --git a/modules/nixos-modules/server/postgres/impermanence.nix b/modules/nixos-modules/server/postgres/impermanence.nix new file mode 100644 index 0000000..a67fb1a --- /dev/null +++ b/modules/nixos-modules/server/postgres/impermanence.nix @@ -0,0 +1,27 @@ +{ + config, + lib, + ... +}: let + dataDir = "/var/lib/postgresql/16"; +in { + config = lib.mkIf (config.services.postgresql.enable && config.host.impermanence.enable) { + assertions = [ + { + assertion = config.services.postgresql.dataDir == dataDir; + message = "postgres data directory does not match persistence"; + } + ]; + environment.persistence."/persist/system/root" = { + enable = true; + hideMounts = true; + directories = [ + { + directory = dataDir; + user = "postgres"; + group = "postgres"; + } + ]; + }; + }; +} diff --git a/modules/nixos-modules/server/postgres/postgres.nix b/modules/nixos-modules/server/postgres/postgres.nix new file mode 100644 index 0000000..af7d1b4 --- /dev/null +++ b/modules/nixos-modules/server/postgres/postgres.nix @@ -0,0 +1,122 @@ +{ + config, + lib, + pkgs, + ... +}: let + enabledDatabases = lib.filterAttrs (_: db: db.enable) config.services.postgresql.databases; + extraDatabasesList = config.services.postgresql.extraDatabases; + + serviceDatabaseUsers = lib.mapAttrsToList (_: db: { + name = db.user; + ensureDBOwnership = true; + }) (lib.filterAttrs (_: db: db.ensureUser) enabledDatabases); + + extraDatabaseUsers = + builtins.map (dbName: { + name = dbName; + ensureDBOwnership = true; + }) + extraDatabasesList; + + serviceDatabases = lib.mapAttrsToList (_: db: db.database) enabledDatabases; + extraDatabaseNames = extraDatabasesList; + + serviceUserMappings = lib.mapAttrsToList (_: db: "user_map ${db.user} ${db.user}") enabledDatabases; + extraUserMappings = builtins.map (dbName: "user_map ${dbName} ${dbName}") extraDatabasesList; + + builtinServiceMappings = let + forgejoMapping = lib.optional (config.services.forgejo.enable && config.services.forgejo.database.type == "postgres") "user_map forgejo forgejo"; + immichMapping = lib.optional (config.services.immich.enable && config.services.immich.database.enable) "user_map immich immich"; + paperlessMapping = lib.optional (config.services.paperless.enable && config.services.paperless.database.createLocally) "user_map paperless paperless"; + in + forgejoMapping ++ immichMapping ++ paperlessMapping; +in { + options = { + services.postgresql = { + databases = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule ({name, ...}: { + options = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Whether to create this database and user"; + }; + user = lib.mkOption { + type = lib.types.str; + default = name; + description = "Database user name"; + }; + database = lib.mkOption { + type = lib.types.str; + default = name; + description = "Database name"; + }; + ensureUser = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Whether to ensure the user exists"; + }; + }; + })); + default = {}; + description = "Databases to create for services"; + }; + + extraDatabases = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = []; + description = "Additional databases to create (user name will match database name)"; + example = ["custom_db" "test_db"]; + }; + + adminUsers = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = []; + description = "System users who should have PostgreSQL superuser access"; + example = ["leyla" "admin"]; + }; + }; + }; + + config = lib.mkIf config.services.postgresql.enable { + services = { + postgresql = { + package = pkgs.postgresql_16; + + ensureUsers = + [ + {name = "postgres";} + ] + ++ serviceDatabaseUsers ++ extraDatabaseUsers; + + ensureDatabases = serviceDatabases ++ extraDatabaseNames; + + identMap = + '' + # ArbitraryMapName systemUser DBUser + + # Administration Users + superuser_map root postgres + superuser_map postgres postgres + '' + + ( + lib.strings.concatLines (builtins.map (user: "superuser_map ${user} postgres") config.services.postgresql.adminUsers) + ) + + '' + + # Client Users + '' + + ( + lib.strings.concatLines (serviceUserMappings ++ extraUserMappings ++ builtinServiceMappings) + ); + + authentication = pkgs.lib.mkOverride 10 '' + # type database DBuser origin-address auth-method optional_ident_map + local all postgres peer map=superuser_map + local sameuser all peer map=user_map + ''; + }; + }; + }; +} diff --git a/modules/nixos-modules/server/qbittorent.nix b/modules/nixos-modules/server/qbittorent.nix deleted file mode 100644 index 2d54587..0000000 --- a/modules/nixos-modules/server/qbittorent.nix +++ /dev/null @@ -1,65 +0,0 @@ -{ - lib, - config, - ... -}: let - qbittorent_profile_directory = "/var/lib/qBittorrent/"; -in { - options.services.qbittorrent = { - mediaDir = lib.mkOption { - type = lib.types.path; - description = lib.mdDoc '' - The directory to create to store qbittorrent media. - ''; - }; - }; - - config = lib.mkIf config.services.qbittorrent.enable (lib.mkMerge [ - (lib.mkIf config.host.impermanence.enable { - fileSystems."/persist/system/qbittorrent".neededForBoot = true; - - host.storage.pool.extraDatasets = { - # sops age key needs to be available to pre persist for user generation - "persist/system/qbittorrent" = { - type = "zfs_fs"; - mountpoint = "/persist/system/qbittorrent"; - options = { - canmount = "on"; - }; - }; - }; - - assertions = [ - { - assertion = config.services.qbittorrent.profileDir == qbittorent_profile_directory; - message = "qbittorrent data directory does not match persistence"; - } - ]; - - environment.persistence = { - "/persist/system/root" = { - directories = [ - { - directory = qbittorent_profile_directory; - user = "qbittorrent"; - group = "qbittorrent"; - } - ]; - }; - - "/persist/system/qbittorrent" = { - enable = true; - hideMounts = true; - directories = [ - { - directory = config.services.qbittorrent.mediaDir; - user = "qbittorrent"; - group = "qbittorrent"; - mode = "1775"; - } - ]; - }; - }; - }) - ]); -} diff --git a/modules/nixos-modules/server/qbittorent/default.nix b/modules/nixos-modules/server/qbittorent/default.nix new file mode 100644 index 0000000..f7511e6 --- /dev/null +++ b/modules/nixos-modules/server/qbittorent/default.nix @@ -0,0 +1,6 @@ +{...}: { + imports = [ + ./qbittorent.nix + ./impermanence.nix + ]; +} diff --git a/modules/nixos-modules/server/qbittorent/impermanence.nix b/modules/nixos-modules/server/qbittorent/impermanence.nix new file mode 100644 index 0000000..1489e7d --- /dev/null +++ b/modules/nixos-modules/server/qbittorent/impermanence.nix @@ -0,0 +1,61 @@ +{ + lib, + config, + ... +}: let + qbittorent_profile_directory = "/var/lib/qBittorrent/"; +in { + options.services.qbittorrent = { + impermanence.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.qbittorrent.enable && config.host.impermanence.enable; + }; + }; + + config = lib.mkIf config.services.qbittorrent.impermanence.enable { + fileSystems."/persist/system/qbittorrent".neededForBoot = true; + + host.storage.pool.extraDatasets = { + # sops age key needs to be available to pre persist for user generation + "persist/system/qbittorrent" = { + type = "zfs_fs"; + mountpoint = "/persist/system/qbittorrent"; + options = { + canmount = "on"; + }; + }; + }; + + assertions = [ + { + assertion = config.services.qbittorrent.profileDir == qbittorent_profile_directory; + message = "qbittorrent data directory does not match persistence"; + } + ]; + + environment.persistence = { + "/persist/system/root" = { + directories = [ + { + directory = qbittorent_profile_directory; + user = "qbittorrent"; + group = "qbittorrent"; + } + ]; + }; + + "/persist/system/qbittorrent" = { + enable = true; + hideMounts = true; + directories = [ + { + directory = config.services.qbittorrent.mediaDir; + user = "qbittorrent"; + group = "qbittorrent"; + mode = "1775"; + } + ]; + }; + }; + }; +} diff --git a/modules/nixos-modules/server/qbittorent/qbittorent.nix b/modules/nixos-modules/server/qbittorent/qbittorent.nix new file mode 100644 index 0000000..44603c8 --- /dev/null +++ b/modules/nixos-modules/server/qbittorent/qbittorent.nix @@ -0,0 +1,18 @@ +{ + lib, + config, + ... +}: { + options.services.qbittorrent = { + mediaDir = lib.mkOption { + type = lib.types.path; + description = lib.mdDoc '' + The directory to create to store qbittorrent media. + ''; + }; + }; + + config = lib.mkIf config.services.qbittorrent.enable { + # Main qbittorrent configuration goes here if needed + }; +} diff --git a/modules/nixos-modules/server/radarr/default.nix b/modules/nixos-modules/server/radarr/default.nix index f39d940..86dbb4b 100644 --- a/modules/nixos-modules/server/radarr/default.nix +++ b/modules/nixos-modules/server/radarr/default.nix @@ -1,6 +1,5 @@ {...}: { imports = [ - ./proxy.nix ./impermanence.nix ]; } diff --git a/modules/nixos-modules/server/radarr/impermanence.nix b/modules/nixos-modules/server/radarr/impermanence.nix index 4a3242c..c948e3a 100644 --- a/modules/nixos-modules/server/radarr/impermanence.nix +++ b/modules/nixos-modules/server/radarr/impermanence.nix @@ -5,7 +5,14 @@ }: let radarr_data_directory = "/var/lib/radarr/.config/Radarr"; in { - config = lib.mkIf (config.services.radarr.enable && config.host.impermanence.enable) { + options.services.radarr = { + impermanence.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.radarr.enable && config.host.impermanence.enable; + }; + }; + + config = lib.mkIf config.services.radarr.impermanence.enable { assertions = [ { assertion = config.services.radarr.dataDir == radarr_data_directory; diff --git a/modules/nixos-modules/server/radarr/proxy.nix b/modules/nixos-modules/server/radarr/proxy.nix deleted file mode 100644 index ec5f575..0000000 --- a/modules/nixos-modules/server/radarr/proxy.nix +++ /dev/null @@ -1,28 +0,0 @@ -{ - lib, - config, - ... -}: { - options.services.radarr = { - subdomain = lib.mkOption { - type = lib.types.nullOr lib.types.str; - default = null; - description = "Subdomain for reverse proxy. If null, service will be local only."; - }; - extraSubdomains = lib.mkOption { - type = lib.types.listOf lib.types.str; - default = []; - description = "Extra subdomains for reverse proxy."; - }; - }; - - config = lib.mkIf (config.services.radarr.enable && config.services.radarr.subdomain != null) { - host.reverse_proxy.subdomains.radarr = { - subdomain = config.services.radarr.subdomain; - extraSubdomains = config.services.radarr.extraSubdomains; - target = "http://127.0.0.1:7878"; - websockets.enable = true; - forwardHeaders.enable = true; - }; - }; -} diff --git a/modules/nixos-modules/server/reverseProxy/default.nix b/modules/nixos-modules/server/reverseProxy/default.nix new file mode 100644 index 0000000..5d57175 --- /dev/null +++ b/modules/nixos-modules/server/reverseProxy/default.nix @@ -0,0 +1,6 @@ +{...}: { + imports = [ + ./reverseProxy.nix + ./impermanence.nix + ]; +} diff --git a/modules/nixos-modules/server/reverseProxy/impermanence.nix b/modules/nixos-modules/server/reverseProxy/impermanence.nix new file mode 100644 index 0000000..7af55df --- /dev/null +++ b/modules/nixos-modules/server/reverseProxy/impermanence.nix @@ -0,0 +1,21 @@ +{ + lib, + config, + ... +}: let + dataDir = "/var/lib/acme"; +in { + config = lib.mkIf (config.host.impermanence.enable && config.services.reverseProxy.enable) { + environment.persistence."/persist/system/root" = { + enable = true; + hideMounts = true; + directories = [ + { + directory = dataDir; + user = "acme"; + group = "acme"; + } + ]; + }; + }; +} diff --git a/modules/nixos-modules/server/reverseProxy/reverseProxy.nix b/modules/nixos-modules/server/reverseProxy/reverseProxy.nix new file mode 100644 index 0000000..eecc9bf --- /dev/null +++ b/modules/nixos-modules/server/reverseProxy/reverseProxy.nix @@ -0,0 +1,176 @@ +{ + lib, + config, + ... +}: { + options.services.reverseProxy = { + enable = lib.mkEnableOption "turn on the reverse proxy"; + openFirewall = lib.mkEnableOption "open the firewall"; + refuseUnmatchedDomains = lib.mkOption { + type = lib.types.bool; + description = "refuse connections for domains that don't match any configured virtual hosts"; + default = true; + }; + ports = { + http = lib.mkOption { + type = lib.types.port; + description = "HTTP port for the reverse proxy"; + default = 80; + }; + https = lib.mkOption { + type = lib.types.port; + description = "HTTPS port for the reverse proxy"; + default = 443; + }; + }; + acme = { + enable = lib.mkOption { + type = lib.types.bool; + description = "enable ACME certificate management"; + default = true; + }; + email = lib.mkOption { + type = lib.types.str; + description = "email address for ACME certificate registration"; + }; + }; + services = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule ({name, ...}: { + options = { + target = lib.mkOption { + type = lib.types.str; + description = "what url will all traffic to this application be forwarded to"; + }; + domain = lib.mkOption { + type = lib.types.str; + description = "what is the default subdomain to be used for this application to be used for"; + default = name; + }; + extraDomains = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "extra domains that should be configured for this domain"; + default = []; + }; + settings = { + certificateRenewal.enable = lib.mkOption { + type = lib.types.bool; + description = "auto renew certificates"; + default = true; + }; + forceSSL.enable = lib.mkOption { + type = lib.types.bool; + description = "auto renew certificates"; + default = true; + }; + proxyHeaders = { + enable = lib.mkEnableOption "should we proxy headers"; + timeout = lib.mkOption { + type = lib.types.int; + default = 60; + }; + }; + proxyWebsockets.enable = lib.mkEnableOption "should the default config proxy websockets"; + forwardHeaders.enable = lib.mkEnableOption "should the default config contain forward headers"; + noSniff.enable = lib.mkEnableOption "should the no sniff flags be set"; + proxyBuffering.enable = lib.mkOption { + type = lib.types.bool; + description = "should proxy buffering be enabled"; + default = true; + }; + maxBodySize = lib.mkOption { + type = lib.types.nullOr lib.types.int; + description = ""; + default = null; + }; + }; + }; + })); + }; + }; + + config = let + httpPort = config.services.reverseProxy.ports.http; + httpsPort = config.services.reverseProxy.ports.https; + in + lib.mkIf config.services.reverseProxy.enable { + security.acme = lib.mkIf config.services.reverseProxy.acme.enable { + acceptTerms = true; + defaults.email = config.services.reverseProxy.acme.email; + }; + + services.nginx = { + enable = true; + virtualHosts = lib.mkMerge ( + (lib.optionals config.services.reverseProxy.refuseUnmatchedDomains [ + { + "_" = { + default = true; + serverName = "_"; + locations."/" = { + extraConfig = '' + return 444; + ''; + }; + }; + } + ]) + ++ lib.lists.flatten ( + lib.attrsets.mapAttrsToList ( + name: service: let + hostConfig = { + forceSSL = service.settings.forceSSL.enable; + enableACME = service.settings.certificateRenewal.enable; + locations = { + "/" = { + proxyPass = service.target; + proxyWebsockets = service.settings.proxyWebsockets.enable; + recommendedProxySettings = service.settings.forwardHeaders.enable; + extraConfig = let + # Client upload size configuration + maxBodySizeConfig = + lib.optionalString (service.settings.maxBodySize != null) + "client_max_body_size ${toString service.settings.maxBodySize}M;"; + + # Security header configuration + noSniffConfig = + lib.optionalString service.settings.noSniff.enable + "add_header X-Content-Type-Options nosniff;"; + + # Proxy buffering configuration + proxyBufferingConfig = + lib.optionalString (!service.settings.proxyBuffering.enable) + "proxy_buffering off;"; + + # Proxy timeout configuration + proxyTimeoutConfig = + lib.optionalString service.settings.proxyHeaders.enable + '' + proxy_read_timeout ${toString service.settings.proxyHeaders.timeout}s; + proxy_connect_timeout ${toString service.settings.proxyHeaders.timeout}s; + proxy_send_timeout ${toString service.settings.proxyHeaders.timeout}s; + ''; + in + maxBodySizeConfig + noSniffConfig + proxyBufferingConfig + proxyTimeoutConfig; + }; + }; + }; + in ( + [ + { + ${service.domain} = hostConfig; + } + ] + ++ builtins.map (domain: {${domain} = hostConfig;}) + service.extraDomains + ) + ) + config.services.reverseProxy.services + ) + ); + }; + networking.firewall.allowedTCPPorts = lib.mkIf config.services.reverseProxy.openFirewall [ + httpPort + httpsPort + ]; + }; +} diff --git a/modules/nixos-modules/server/reverse_proxy.nix b/modules/nixos-modules/server/reverse_proxy.nix deleted file mode 100644 index 26b4374..0000000 --- a/modules/nixos-modules/server/reverse_proxy.nix +++ /dev/null @@ -1,128 +0,0 @@ -{ - lib, - config, - ... -}: let - dataDir = "/var/lib/acme"; - httpPort = 80; - httpsPort = 443; -in { - options.host.reverse_proxy = { - enable = lib.mkEnableOption "turn on the reverse proxy"; - hostname = lib.mkOption { - type = lib.types.str; - description = "what host name are we going to be proxying from"; - }; - forceSSL = lib.mkOption { - type = lib.types.bool; - description = "force connections to use https"; - default = config.host.reverse_proxy.enableACME; - }; - enableACME = lib.mkOption { - type = lib.types.bool; - description = "auto renew certificates"; - default = true; - }; - subdomains = lib.mkOption { - type = lib.types.attrsOf (lib.types.submodule ({name, ...}: { - options = { - subdomain = lib.mkOption { - type = lib.types.str; - description = "what is the default subdomain to be used for this application to be used for"; - default = name; - }; - extraSubdomains = lib.mkOption { - type = lib.types.listOf lib.types.str; - description = "extra domains that should be configured for this domain"; - default = []; - }; - - target = lib.mkOption { - type = lib.types.str; - description = "what url will all traffic to this application be forwarded to"; - }; - - websockets.enable = lib.mkEnableOption "should the default config proxy websockets"; - - forwardHeaders.enable = lib.mkEnableOption "should the default config contain forward headers"; - - extraConfig = lib.mkOption { - type = lib.types.lines; - default = ""; - description = '' - These lines go to the end of the upstream verbatim. - ''; - }; - }; - })); - }; - }; - - config = lib.mkIf config.host.reverse_proxy.enable (lib.mkMerge [ - { - security.acme = lib.mkIf config.host.reverse_proxy.enableACME { - acceptTerms = true; - defaults.email = "jan-leila@protonmail.com"; - }; - - services.nginx = { - enable = true; - virtualHosts = lib.mkMerge ( - lib.lists.flatten ( - lib.attrsets.mapAttrsToList ( - name: value: let - hostConfig = { - forceSSL = config.host.reverse_proxy.forceSSL; - enableACME = config.host.reverse_proxy.enableACME; - locations = { - "/" = { - proxyPass = value.target; - proxyWebsockets = value.websockets.enable; - recommendedProxySettings = value.forwardHeaders.enable; - extraConfig = - value.extraConfig; - }; - }; - }; - in ( - [ - { - ${"${value.subdomain}.${config.host.reverse_proxy.hostname}"} = hostConfig; - } - ] - ++ builtins.map (subdomain: {${"${subdomain}.${config.host.reverse_proxy.hostname}"} = hostConfig;}) - value.extraSubdomains - ) - ) - config.host.reverse_proxy.subdomains - ) - ); - }; - - networking.firewall.allowedTCPPorts = [ - httpPort - httpsPort - ]; - } - (lib.mkIf config.host.impermanence.enable { - # TODO: figure out how to write an assertion for this - # assertions = [ - # { - # assertion = security.acme.certs..directory == dataDir; - # message = "postgres data directory does not match persistence"; - # } - # ]; - environment.persistence."/persist/system/root" = { - enable = true; - hideMounts = true; - directories = [ - { - directory = dataDir; - user = "acme"; - group = "acme"; - } - ]; - }; - }) - ]); -} diff --git a/modules/nixos-modules/server/searx/default.nix b/modules/nixos-modules/server/searx/default.nix index ac84c1d..5426380 100644 --- a/modules/nixos-modules/server/searx/default.nix +++ b/modules/nixos-modules/server/searx/default.nix @@ -1,63 +1,6 @@ { - config, - lib, - inputs, - ... -}: { imports = [ + ./searx.nix ./proxy.nix ]; - - config = lib.mkIf config.services.searx.enable { - sops.secrets = { - "services/searx" = { - sopsFile = "${inputs.secrets}/defiant-services.yaml"; - }; - }; - - services.searx = { - environmentFile = config.sops.secrets."services/searx".path; - - # Rate limiting - limiterSettings = { - real_ip = { - x_for = 1; - ipv4_prefix = 32; - ipv6_prefix = 56; - }; - - botdetection = { - ip_limit = { - filter_link_local = true; - link_token = true; - }; - }; - }; - - settings = { - server = { - port = 8083; - secret_key = "@SEARXNG_SECRET@"; - }; - - # Search engine settings - search = { - safe_search = 2; - autocomplete_min = 2; - autocomplete = "duckduckgo"; - }; - - # Enabled plugins - enabled_plugins = [ - "Basic Calculator" - "Hash plugin" - "Tor check plugin" - "Open Access DOI rewrite" - "Hostnames plugin" - "Unit converter plugin" - "Tracker URL remover" - ]; - }; - }; - }; } diff --git a/modules/nixos-modules/server/searx/proxy.nix b/modules/nixos-modules/server/searx/proxy.nix index 0c1eae1..e994e4a 100644 --- a/modules/nixos-modules/server/searx/proxy.nix +++ b/modules/nixos-modules/server/searx/proxy.nix @@ -4,18 +4,27 @@ ... }: { options.services.searx = { - subdomain = lib.mkOption { - type = lib.types.str; - description = "subdomain of base domain that searx will be hosted at"; - default = "searx"; + extraDomains = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "extra domains that should be configured for searx"; + default = []; + }; + reverseProxy = { + enable = lib.mkOption { + type = lib.types.bool; + default = config.services.searx.enable && config.services.reverseProxy.enable; + }; }; }; - config = lib.mkIf (config.services.searx.enable && config.host.reverse_proxy.enable) { - host = { - reverse_proxy.subdomains.searx = { - subdomain = config.services.searx.subdomain; - target = "http://localhost:${toString config.services.searx.settings.server.port}"; + config = lib.mkIf config.services.searx.reverseProxy.enable { + services.reverseProxy.services.searx = { + target = "http://localhost:${toString config.services.searx.settings.server.port}"; + domain = config.services.searx.domain; + extraDomains = config.services.searx.extraDomains; + + settings = { + forwardHeaders.enable = true; }; }; }; diff --git a/modules/nixos-modules/server/searx/searx.nix b/modules/nixos-modules/server/searx/searx.nix new file mode 100644 index 0000000..d4d4012 --- /dev/null +++ b/modules/nixos-modules/server/searx/searx.nix @@ -0,0 +1,59 @@ +{ + config, + lib, + inputs, + ... +}: { + config = lib.mkIf config.services.searx.enable { + sops.secrets = { + "services/searx" = { + sopsFile = "${inputs.secrets}/defiant-services.yaml"; + }; + }; + + services.searx = { + environmentFile = config.sops.secrets."services/searx".path; + + # Rate limiting + limiterSettings = { + real_ip = { + x_for = 1; + ipv4_prefix = 32; + ipv6_prefix = 56; + }; + + botdetection = { + ip_limit = { + filter_link_local = true; + link_token = true; + }; + }; + }; + + settings = { + server = { + port = 8083; + secret_key = "@SEARXNG_SECRET@"; + }; + + # Search engine settings + search = { + safe_search = 2; + autocomplete_min = 2; + autocomplete = "duckduckgo"; + }; + + # Enabled plugins + enabled_plugins = [ + "Basic Calculator" + "Hash plugin" + "Tor check plugin" + "Open Access DOI rewrite" + "Hostnames plugin" + "Unit converter plugin" + "Tracker URL remover" + ]; + }; + }; + }; +} diff --git a/modules/nixos-modules/server/sonarr/default.nix b/modules/nixos-modules/server/sonarr/default.nix index f39d940..86dbb4b 100644 --- a/modules/nixos-modules/server/sonarr/default.nix +++ b/modules/nixos-modules/server/sonarr/default.nix @@ -1,6 +1,5 @@ {...}: { imports = [ - ./proxy.nix ./impermanence.nix ]; } diff --git a/modules/nixos-modules/server/sonarr/impermanence.nix b/modules/nixos-modules/server/sonarr/impermanence.nix index abc843c..5b90ee9 100644 --- a/modules/nixos-modules/server/sonarr/impermanence.nix +++ b/modules/nixos-modules/server/sonarr/impermanence.nix @@ -5,7 +5,14 @@ }: let sonarr_data_directory = "/var/lib/sonarr/.config/NzbDrone"; in { - config = lib.mkIf (config.services.sonarr.enable && config.host.impermanence.enable) { + options.services.sonarr = { + impermanence.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.sonarr.enable && config.host.impermanence.enable; + }; + }; + + config = lib.mkIf config.services.sonarr.impermanence.enable { assertions = [ { assertion = config.services.sonarr.dataDir == sonarr_data_directory; diff --git a/modules/nixos-modules/server/sonarr/proxy.nix b/modules/nixos-modules/server/sonarr/proxy.nix deleted file mode 100644 index 22b90a6..0000000 --- a/modules/nixos-modules/server/sonarr/proxy.nix +++ /dev/null @@ -1,28 +0,0 @@ -{ - lib, - config, - ... -}: { - options.services.sonarr = { - subdomain = lib.mkOption { - type = lib.types.nullOr lib.types.str; - default = null; - description = "Subdomain for reverse proxy. If null, service will be local only."; - }; - extraSubdomains = lib.mkOption { - type = lib.types.listOf lib.types.str; - default = []; - description = "Extra subdomains for reverse proxy."; - }; - }; - - config = lib.mkIf (config.services.sonarr.enable && config.services.sonarr.subdomain != null) { - host.reverse_proxy.subdomains.sonarr = { - subdomain = config.services.sonarr.subdomain; - extraSubdomains = config.services.sonarr.extraSubdomains; - target = "http://127.0.0.1:8989"; - websockets.enable = true; - forwardHeaders.enable = true; - }; - }; -} diff --git a/modules/nixos-modules/server/wyoming.nix b/modules/nixos-modules/server/wyoming.nix index 4894dd4..c9a1474 100644 --- a/modules/nixos-modules/server/wyoming.nix +++ b/modules/nixos-modules/server/wyoming.nix @@ -37,9 +37,9 @@ openwakeword = { enable = true; uri = "tcp://0.0.0.0:10400"; - preloadModels = [ - "ok_nabu" - ]; + # preloadModels = [ + # "ok_nabu" + # ]; # TODO: custom models }; }; diff --git a/modules/nixos-modules/ssh.nix b/modules/nixos-modules/ssh.nix index 6f5fac1..0a82116 100644 --- a/modules/nixos-modules/ssh.nix +++ b/modules/nixos-modules/ssh.nix @@ -16,6 +16,8 @@ }; }; }; + + programs.ssh.kexAlgorithms = config.services.openssh.settings.KexAlgorithms; } (lib.mkIf config.host.impermanence.enable { environment.persistence."/persist/system/root" = { diff --git a/modules/nixos-modules/sync.nix b/modules/nixos-modules/sync.nix index bf43041..96f54d5 100644 --- a/modules/nixos-modules/sync.nix +++ b/modules/nixos-modules/sync.nix @@ -1,7 +1,7 @@ { config, lib, - outputs, + syncthingConfiguration, ... }: let mountDir = "/mnt/sync"; @@ -27,7 +27,7 @@ in { configDir = configDir; overrideDevices = true; overrideFolders = true; - configuration = outputs.syncthingConfiguration; + configuration = syncthingConfiguration; deviceName = config.networking.hostName; }; } diff --git a/rebuild.sh b/rebuild.sh index 6750450..48746d9 100755 --- a/rebuild.sh +++ b/rebuild.sh @@ -18,6 +18,7 @@ else fi show_trace=false +clean_vm=false while [ $# -gt 0 ]; do case "$1" in @@ -50,6 +51,9 @@ while [ $# -gt 0 ]; do --show-trace) show_trace=true ;; + --clean-vm) + clean_vm=true + ;; --help|-h) echo "--help -h: print this message" echo "--target -t: defaults to the current system" @@ -58,6 +62,8 @@ while [ $# -gt 0 ]; do echo " currently: ${target:-$default_target}" echo "--mode -m: defaults to 'switch', but 'test' on non-main branches" echo " currently would be: $default_mode" + echo " Available modes: switch, test, build, boot, vm" + echo " 'vm' mode builds and starts a virtual machine" echo "--user -u: defaults to the current user" echo " currently: $default_user" echo "--host: defaults to building on the current machine" @@ -65,6 +71,7 @@ while [ $# -gt 0 ]; do echo "--preserve-result: do not remove the generated result folder after building" echo "--no-preserve-result: remove any result folder after building" echo "--show-trace: show trace on builds" + echo "--clean-vm: remove existing VM disk (nixos.qcow2) before building" echo "" echo "Branch-aware behavior:" echo " - On non-main branches: defaults to test mode with warning" @@ -90,6 +97,20 @@ flake=${flake:-$target} mode=${mode:-$default_mode} user=${user:-$default_user} +# Validate mode +valid_modes="switch test build boot vm" +if [[ ! " $valid_modes " =~ " $mode " ]]; then + echo "Error: Invalid mode '$mode'" + echo "Valid modes are: $valid_modes" + exit 1 +fi + +# Clean VM disk if requested +if [[ "$clean_vm" = true ]] && [[ -f "nixos.qcow2" ]]; then + echo "Removing existing VM disk: nixos.qcow2" + rm nixos.qcow2 +fi + # Branch-aware warnings and behavior if [[ "$current_branch" != "main" ]] && [[ "$mode" == "test" ]]; then echo "⚠️ WARNING: You are on branch '$current_branch' (not main)" @@ -101,26 +122,39 @@ elif [[ "$current_branch" == "main" ]] && [[ -n "$git_status" ]] && [[ "$mode" ! echo " git checkout -b feature/your-feature-name" fi -command="nixos-rebuild $mode --sudo --ask-sudo-password --flake .#$flake" +if [[ "$mode" == "vm" ]]; then + command="nix build .#nixosConfigurations.$flake.config.system.build.vm" + + if [[ "$show_trace" = true ]]; then + command="$command --show-trace" + fi + + echo $command + $command + + if [[ $? -eq 0 ]] && [[ -d "result" ]]; then + echo "Starting VM..." + QEMU_KERNEL_PARAMS=console=ttyS0 ./result/bin/run-nixos-vm -nographic; reset + fi +else + command="nixos-rebuild $mode --sudo --ask-sudo-password --flake .#$flake" + + if [[ $host ]]; then + command="$command --build-host $host" + fi -if [[ $host ]]; -then - command="$command --build-host $host" + if [[ "$target" != "$(hostname)" ]]; then + command="$command --target-host $user@$target" + fi + + if [[ "$show_trace" = true ]]; then + command="$command --show-trace" + fi + + echo $command + $command fi -if [[ "$target" != "$(hostname)" ]]; -then - command="$command --target-host $user@$target" -fi - -if [[ "$show_trace" = true ]]; -then - command="$command --show-trace" -fi - -echo $command -$command - if [ -d "result" ]; then if [[ "$preserve_result" == "false" ]]; diff --git a/util/default.nix b/util/default.nix index fb2f83d..66e300b 100644 --- a/util/default.nix +++ b/util/default.nix @@ -52,6 +52,12 @@ home-manager-config ../modules/system-modules ]; + + syncthingConfiguration = nix-syncthing.lib.syncthingConfiguration { + modules = [ + (import ../configurations/syncthing) + ]; + }; in { forEachPkgs = lambda: forEachSystem (system: lambda system (pkgsFor system)); @@ -62,19 +68,9 @@ in { (lib.mkUnless condition no) ]; - mkNixosInstaller = host: userKeys: - nixpkgs.lib.nixosSystem { - modules = [ - { - # TODO: authorized keys for all users and hosts - } - ../configurations/nixos/${host} - ]; - }; - mkNixosSystem = host: nixpkgs.lib.nixosSystem { - specialArgs = {inherit inputs outputs util;}; + specialArgs = {inherit inputs outputs util syncthingConfiguration;}; modules = system-modules ++ [ @@ -83,7 +79,7 @@ in { impermanence.nixosModules.impermanence home-manager.nixosModules.home-manager disko.nixosModules.disko - lix-module.nixosModules.default + # lix-module.nixosModules.default ../modules/nixos-modules ../configurations/nixos/${host} ]; @@ -119,10 +115,4 @@ in { ../configurations/home-manager/${user} ]; }; - - syncthingConfiguration = nix-syncthing.lib.syncthingConfiguration { - modules = [ - (import ../configurations/syncthing) - ]; - }; }