From f185566ea303c13a58f94b06f454801a068e1704 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Charlotte=20=F0=9F=A6=9D=20Delenk?= Date: Sun, 12 Jun 2022 16:37:09 +0100 Subject: [PATCH] use packages from nix-packages --- config/services/mastodon.nix | 4 +- config/services/matrix-media-repo.nix | 4 +- config/services/old-homepage.nix | 8 +- config/services/reverse-proxy.nix | 6 +- config/users/miifox.nix | 4 +- flake.lock | 135 +- flake.nix | 4 +- modules/matrix/mautrix-whatsapp.nix | 4 +- modules/minecraft/server.nix | 4 +- packages/mastodon/default.nix | 138 - packages/mastodon/gemset.nix | 3121 ----------------------- packages/mastodon/source.nix | 11 - packages/mastodon/update.nix | 30 - packages/mastodon/update.sh | 98 - packages/mastodon/version.nix | 1 - packages/matrix/matrix-media-repo.nix | 30 - packages/matrix/matrix-media-repo.patch | 1179 --------- packages/matrix/mautrix-whatsapp.nix | 16 - packages/miifox.nix | 17 - packages/minecraft/paper.nix | 37 - packages/old-homepage.nix | 6 - 21 files changed, 129 insertions(+), 4728 deletions(-) delete mode 100644 packages/mastodon/default.nix delete mode 100644 packages/mastodon/gemset.nix delete mode 100644 packages/mastodon/source.nix delete mode 100644 packages/mastodon/update.nix delete mode 100755 packages/mastodon/update.sh delete mode 100644 packages/mastodon/version.nix delete mode 100644 packages/matrix/matrix-media-repo.nix delete mode 100644 packages/matrix/matrix-media-repo.patch delete mode 100644 packages/matrix/mautrix-whatsapp.nix delete mode 100644 packages/miifox.nix delete mode 100644 packages/minecraft/paper.nix delete mode 100644 packages/old-homepage.nix diff --git a/config/services/mastodon.nix b/config/services/mastodon.nix index cf5ce6af..235f2893 100644 --- a/config/services/mastodon.nix +++ b/config/services/mastodon.nix @@ -1,4 +1,4 @@ -{ pkgs, config, lib, ... }: +{ nix-packages, system, pkgs, config, lib, ... }: let listenIPs = (import ../../utils/getInternalIP.nix config).listenIPs; listenStatements = lib.concatStringsSep "\n" (builtins.map (ip: "listen ${ip}:443 http3;") listenIPs) + '' @@ -12,7 +12,7 @@ let "mastodon-sidekiq.service" ]; }; - mastodon = pkgs.callPackage ../../packages/mastodon { }; + mastodon = nix-packages.packages.${system}.mastodon; in { imports = [ diff --git a/config/services/matrix-media-repo.nix b/config/services/matrix-media-repo.nix index 7f6b215f..429c1d36 100644 --- a/config/services/matrix-media-repo.nix +++ b/config/services/matrix-media-repo.nix @@ -1,6 +1,6 @@ -{ config, pkgs, lib, ... }: +{ nix-packages, system, config, pkgs, lib, ... }: let - matrix-media-repo = pkgs.callPackage ../../packages/matrix/matrix-media-repo.nix { }; + matrix-media-repo = nix-packages.packages.${system}.matrix-media-repo; config-yml = pkgs.writeText "matrix-media-repo.yaml" (lib.generators.toYAML { } { repo = { bindAddress = "127.0.0.1"; diff --git a/config/services/old-homepage.nix b/config/services/old-homepage.nix index 2bee6eca..4e1df885 100644 --- a/config/services/old-homepage.nix +++ b/config/services/old-homepage.nix @@ -1,14 +1,14 @@ -{ ... }: +{ nix-packages, system, ... }: let - homepage-old = import ../../packages/old-homepage.nix { }; + homepage-old = nix-packages.packages.${system}.homepage-old; in { systemd.services.homepage-old = { enable = true; description = "darkkirb.de"; - script = "${homepage-old.homepage-old}/homepage"; + script = "${homepage-old}/homepage"; serviceConfig = { - WorkingDirectory = homepage-old.homepage-old; + WorkingDirectory = homepage-old; EnvironmentFile = "/run/secrets/services/old-homepage"; }; wantedBy = [ "multi-user.target" ]; diff --git a/config/services/reverse-proxy.nix b/config/services/reverse-proxy.nix index 1553de63..f7e27d99 100644 --- a/config/services/reverse-proxy.nix +++ b/config/services/reverse-proxy.nix @@ -1,4 +1,4 @@ -{ pkgs, config, ... }: { +{ nix-packages, system, pkgs, config, ... }: { services.nginx.virtualHosts."hydra.chir.rs" = { sslCertificate = "/var/lib/acme/chir.rs/cert.pem"; sslCertificateKey = "/var/lib/acme/chir.rs/key.pem"; @@ -11,7 +11,9 @@ }; }; services.nginx.virtualHosts."mastodon.chir.rs" = - let mastodon = pkgs.callPackage ../../packages/mastodon { }; in + let + mastodon = nix-packages.packages.${system}.mastodon; + in { sslCertificate = "/var/lib/acme/chir.rs/cert.pem"; sslCertificateKey = "/var/lib/acme/chir.rs/key.pem"; diff --git a/config/users/miifox.nix b/config/users/miifox.nix index 066f25d8..91abf3f5 100644 --- a/config/users/miifox.nix +++ b/config/users/miifox.nix @@ -1,4 +1,4 @@ -{ pkgs, miifox-net, ... }: { +{ pkgs, nix-packages, system, ... }: { users.users.miifox = { createHome = true; description = "Miifox"; @@ -27,7 +27,7 @@ sslCertificateKey = "/var/lib/acme/miifox.net/key.pem"; locations."/" = let - miifox-website = pkgs.callPackage (import ../../packages/miifox.nix miifox-net) { }; + miifox-website = nix-packages.packages.${system}.miifox-net; in { root = "${miifox-website}"; diff --git a/flake.lock b/flake.lock index 946273ef..955895dc 100644 --- a/flake.lock +++ b/flake.lock @@ -181,6 +181,25 @@ "type": "github" } }, + "gomod2nix": { + "inputs": { + "nixpkgs": "nixpkgs_4", + "utils": "utils" + }, + "locked": { + "lastModified": 1654019497, + "narHash": "sha256-yj53tEaOAJoZ1iEBbZ4TArpgAsLZnmivfr4eD0xF52c=", + "owner": "tweag", + "repo": "gomod2nix", + "rev": "71c797eb0d83f33de7e0247b3ffe7120d98c6b49", + "type": "github" + }, + "original": { + "owner": "tweag", + "repo": "gomod2nix", + "type": "github" + } + }, "home-manager": { "inputs": { "nixpkgs": [ @@ -275,23 +294,55 @@ "type": "github" } }, - "miifox-net": { + "mastodon": { "flake": false, "locked": { - "lastModified": 1648216492, - "narHash": "sha256-OKGPwQZjZXbXziJLSOE8K/0fCWCnvU/I2Lm3Vc8KD/o=", - "ref": "refs/heads/master", - "rev": "7826b9a3bec5dddd4b8a879c3396a1406fc37370", - "revCount": 5, - "type": "git", - "url": "https://git.chir.rs/CarolineHusky/MiiFox.net" + "lastModified": 1654881571, + "narHash": "sha256-ASSrCM0jHMI04U7fFPQdaeDvt/sHzpiWKHSy6+/FW0M=", + "owner": "glitch-soc", + "repo": "mastodon", + "rev": "970f06331bc7e482226e974c468b559a9e2f3fa3", + "type": "github" }, "original": { - "type": "git", - "url": "https://git.chir.rs/CarolineHusky/MiiFox.net" + "owner": "glitch-soc", + "repo": "mastodon", + "type": "github" } }, - "miifox-net_2": { + "matrix-media-repo": { + "flake": false, + "locked": { + "lastModified": 1648768263, + "narHash": "sha256-H1S9l5S4gcVU482qYCpDW+Ki0r8VkwBgkbUCk6k63sg=", + "owner": "turt2live", + "repo": "matrix-media-repo", + "rev": "3184dbc7720fc103aaf4704be894eac69535e887", + "type": "github" + }, + "original": { + "owner": "turt2live", + "repo": "matrix-media-repo", + "type": "github" + } + }, + "mautrix-whatsapp": { + "flake": false, + "locked": { + "lastModified": 1654374800, + "narHash": "sha256-8Jm1Z4pCmHBIZ+TNy2DFX/vQwYqeH4k2XtIoYkeoF3Y=", + "owner": "mautrix", + "repo": "whatsapp", + "rev": "0796d14133c19d5e18223b6f138835229b7acf10", + "type": "github" + }, + "original": { + "owner": "mautrix", + "repo": "whatsapp", + "type": "github" + } + }, + "miifox-net": { "flake": false, "locked": { "lastModified": 1648216492, @@ -348,17 +399,22 @@ "inputs": { "clean-s3-cache": "clean-s3-cache", "flake-utils": "flake-utils_4", - "miifox-net": "miifox-net_2", + "gomod2nix": "gomod2nix", + "mastodon": "mastodon", + "matrix-media-repo": "matrix-media-repo", + "mautrix-whatsapp": "mautrix-whatsapp", + "miifox-net": "miifox-net", "nixpkgs": [ "nixpkgs" - ] + ], + "nixpkgs-go116": "nixpkgs-go116" }, "locked": { - "lastModified": 1654974491, - "narHash": "sha256-T4Kf3mgVu4QRxJqEMvIM0UvtCKwU4Jp6OaJYMFXf2PI=", + "lastModified": 1655044097, + "narHash": "sha256-zxkgayMFhrXCfO8Z8yycy04EwOtXggxFxqoGrbz1vW4=", "owner": "DarkKirb", "repo": "nix-packages", - "rev": "1c7b6c474494809cdc36a70d49b4d6f8f28617fc", + "rev": "03667319ca6732486e1761aa468328cf295e2723", "type": "github" }, "original": { @@ -509,11 +565,27 @@ }, "nixpkgs_4": { "locked": { - "lastModified": 1655003801, - "narHash": "sha256-V0NaVMDKQO/LxyKqD++5jEQGOHzfx1JzFGz7hHPly2U=", + "lastModified": 1653581809, + "narHash": "sha256-Uvka0V5MTGbeOfWte25+tfRL3moECDh1VwokWSZUdoY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "18bd58aa85947bdef47ae3a601fff2d81de0b2d3", + "rev": "83658b28fe638a170a19b8933aa008b30640fbd1", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_5": { + "locked": { + "lastModified": 1655046959, + "narHash": "sha256-gxqHZKq1ReLDe6ZMJSbmSZlLY95DsVq5o6jQihhzvmw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "07bf3d25ce1da3bee6703657e6a787a4c6cdcea9", "type": "github" }, "original": { @@ -546,11 +618,11 @@ ] }, "locked": { - "lastModified": 1654969551, - "narHash": "sha256-mcQIDMKK1yloAByYk6mnuG21K/mDznHWdmd2zHGZcRY=", + "lastModified": 1655023857, + "narHash": "sha256-Kspm/iGHRMe/1wgmlBKIybHUHxPe/PwtHtq1p/zDN7o=", "owner": "PolyMC", "repo": "PolyMC", - "rev": "2bd8e7dca4aa55c836cb0bf33dc8d4be84fc938c", + "rev": "c4f2e3a95584d9c50544a978a83650f8f83551fa", "type": "github" }, "original": { @@ -567,12 +639,10 @@ "home-manager": "home-manager", "hosts-list": "hosts-list", "hydra": "hydra", - "miifox-net": "miifox-net", "nix": "nix", "nix-packages": "nix-packages", "nixos-hardware": "nixos-hardware", - "nixpkgs": "nixpkgs_4", - "nixpkgs-go116": "nixpkgs-go116", + "nixpkgs": "nixpkgs_5", "nixpkgs-noto-variable": "nixpkgs-noto-variable", "nur": "nur", "polymc": "polymc", @@ -625,6 +695,21 @@ "repo": "sops-nix", "type": "github" } + }, + "utils": { + "locked": { + "lastModified": 1653893745, + "narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 8a4599d8..a912b2ff 100644 --- a/flake.nix +++ b/flake.nix @@ -21,10 +21,7 @@ rec { hosts-list.url = github:StevenBlack/hosts; hosts-list.flake = false; nixos-hardware.url = github:NixOS/nixos-hardware; - miifox-net.url = "git+https://git.chir.rs/CarolineHusky/MiiFox.net"; - miifox-net.flake = false; nixpkgs-noto-variable.url = github:NixOS/nixpkgs/1988f9a17fc1c2ab11f5817adf34a4eb8d06454d; - nixpkgs-go116.url = github:NixOS/nixpkgs/dab5668f6be905a7f0de39a7d67fd8f78a13d600; nix-packages.url = github:DarkKirb/nix-packages/main; nix-packages.inputs.nixpkgs.follows = "nixpkgs"; @@ -103,6 +100,7 @@ rec { github-cli ]; }; + formatters.x86_64-linux = nixpkgs.legacyPackages.x86_64-linux.alejandra; hydraJobs = (builtins.listToAttrs (map ({ name, system }: { inherit name; diff --git a/modules/matrix/mautrix-whatsapp.nix b/modules/matrix/mautrix-whatsapp.nix index 126013c1..29addad7 100644 --- a/modules/matrix/mautrix-whatsapp.nix +++ b/modules/matrix/mautrix-whatsapp.nix @@ -1,4 +1,4 @@ -{ config, pkgs, lib, ... }: +{ nix-packages, system, config, pkgs, lib, ... }: with lib; let dataDir = "/var/lib/mautrix-whatsapp"; @@ -7,7 +7,7 @@ let settingsFormat = pkgs.formats.yaml { }; settingsFileUnsubstituted = settingsFormat.generate "mautrix-telegram-whatsapp-unsubstituted.yaml" cfg.settings; settingsFile = "${dataDir}/config.yaml"; - mautrix-whatsapp = pkgs.callPackage ../../packages/matrix/mautrix-whatsapp.nix { }; + mautrix-whatsapp = nix-packages.packages.${system}.mautrix-whatsapp; in { options = { diff --git a/modules/minecraft/server.nix b/modules/minecraft/server.nix index b41fee99..5b67b338 100644 --- a/modules/minecraft/server.nix +++ b/modules/minecraft/server.nix @@ -1,7 +1,7 @@ -{ config, lib, options, pkgs, ... }: +{ nix-packages, system, config, lib, options, pkgs, ... }: with lib; let - papermc = pkgs.callPackage ../../packages/minecraft/paper.nix { }; + papermc = nix-packages.packages.${system}.papermc; cfg = config.services.minecraft; opt = options.services.minecraft; serverProperties = pkgs.writeText "server.properties" '' diff --git a/packages/mastodon/default.nix b/packages/mastodon/default.nix deleted file mode 100644 index e2eb3122..00000000 --- a/packages/mastodon/default.nix +++ /dev/null @@ -1,138 +0,0 @@ -{ lib -, stdenv -, nodejs-slim -, mkYarnPackage -, fetchFromGitHub -, bundlerEnv -, nixosTests -, yarn -, callPackage -, imagemagick -, ffmpeg -, file -, ruby_3_0 -, writeShellScript -, fetchYarnDeps -, fixup_yarn_lock - - # Allow building a fork or custom version of Mastodon: -, pname ? "mastodon-glitch" -, version ? import ./version.nix -, srcOverride ? null -, dependenciesDir ? ./. # Should contain gemset.nix, yarn.nix and package.json. -}: - -stdenv.mkDerivation rec { - inherit pname version; - - # Using overrideAttrs on src does not build the gems and modules with the overridden src. - # Putting the callPackage up in the arguments list also does not work. - src = if srcOverride != null then srcOverride else callPackage ./source.nix { }; - - yarnOfflineCache = fetchYarnDeps { - yarnLock = "${src}/yarn.lock"; - sha256 = "sha256-wvzwggDdMqr+XI4K8ZDm13yTuBdqnRwzT78cLnTVAH4="; - }; - - mastodon-gems = bundlerEnv { - name = "${pname}-gems-${version}"; - inherit version; - ruby = ruby_3_0; - gemdir = src; - gemset = dependenciesDir + "/gemset.nix"; - # This fix (copied from https://github.com/NixOS/nixpkgs/pull/76765) replaces the gem - # symlinks with directories, resolving this error when running rake: - # /nix/store/451rhxkggw53h7253izpbq55nrhs7iv0-mastodon-gems-3.0.1/lib/ruby/gems/2.6.0/gems/bundler-1.17.3/lib/bundler/settings.rb:6:in `': uninitialized constant Bundler::Settings (NameError) - postBuild = '' - for gem in "$out"/lib/ruby/gems/*/gems/*; do - cp -a "$gem/" "$gem.new" - rm "$gem" - # needed on macOS, otherwise the mv yields permission denied - chmod +w "$gem.new" - mv "$gem.new" "$gem" - done - ''; - }; - - mastodon-modules = stdenv.mkDerivation { - pname = "${pname}-modules"; - inherit src version; - - nativeBuildInputs = [ fixup_yarn_lock nodejs-slim yarn mastodon-gems mastodon-gems.wrappedRuby ]; - - RAILS_ENV = "production"; - NODE_ENV = "production"; - - buildPhase = '' - export HOME=$PWD - fixup_yarn_lock ~/yarn.lock - yarn config --offline set yarn-offline-mirror ${yarnOfflineCache} - yarn install --offline --frozen-lockfile --ignore-engines --ignore-scripts --no-progress - - patchShebangs ~/bin - patchShebangs ~/node_modules - - # skip running yarn install - rm -rf ~/bin/yarn - - OTP_SECRET=precompile_placeholder SECRET_KEY_BASE=precompile_placeholder \ - rails assets:precompile - yarn cache clean --offline - rm -rf ~/node_modules/.cache - ''; - - installPhase = '' - mkdir -p $out/public - cp -r node_modules $out/node_modules - cp -r public/assets $out/public - cp -r public/packs $out/public - ''; - }; - - propagatedBuildInputs = [ imagemagick ffmpeg file mastodon-gems.wrappedRuby ]; - buildInputs = [ mastodon-gems nodejs-slim ]; - - buildPhase = '' - ln -s ${mastodon-modules}/node_modules node_modules - ln -s ${mastodon-modules}/public/assets public/assets - ln -s ${mastodon-modules}/public/packs public/packs - - patchShebangs bin/ - for b in $(ls ${mastodon-gems}/bin/) - do - if [ ! -f bin/$b ]; then - ln -s ${mastodon-gems}/bin/$b bin/$b - fi - done - - rm -rf log - ln -s /var/log/mastodon log - ln -s /tmp tmp - ''; - - installPhase = - let - run-streaming = writeShellScript "run-streaming.sh" '' - # NixOS helper script to consistently use the same NodeJS version the package was built with. - ${nodejs-slim}/bin/node ./streaming - ''; - in - '' - mkdir -p $out - cp -r * $out/ - ln -s ${run-streaming} $out/run-streaming.sh - ''; - - passthru = { - tests.mastodon = nixosTests.mastodon; - updateScript = callPackage ./update.nix { }; - }; - - meta = with lib; { - description = "Self-hosted, globally interconnected microblogging software based on ActivityPub"; - homepage = "https://joinmastodon.org"; - license = licenses.agpl3Plus; - platforms = [ "x86_64-linux" "i686-linux" "aarch64-linux" ]; - maintainers = with maintainers; [ petabyteboy happy-river erictapen izorkin ]; - }; -} diff --git a/packages/mastodon/gemset.nix b/packages/mastodon/gemset.nix deleted file mode 100644 index 1c5a3ed9..00000000 --- a/packages/mastodon/gemset.nix +++ /dev/null @@ -1,3121 +0,0 @@ -{ - actioncable = { - dependencies = ["actionpack" "activesupport" "nio4r" "websocket-driver"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0p8zkh5ww16y8n1jp12y1gjrmll7m7305c91p419f10qrw4x8cgc"; - type = "gem"; - }; - version = "6.1.6"; - }; - actionmailbox = { - dependencies = ["actionpack" "activejob" "activerecord" "activestorage" "activesupport" "mail"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0z52r7k3ig09zjvfcb8xnrl9vl0ssii22c2h7gx26nq8wb7yjkwq"; - type = "gem"; - }; - version = "6.1.6"; - }; - actionmailer = { - dependencies = ["actionpack" "actionview" "activejob" "activesupport" "mail" "rails-dom-testing"]; - groups = ["default" "development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "186bkhrp8j81nrw5xznbi0nyhk49gdv6ynd80pcyk5lxhfkiw1wc"; - type = "gem"; - }; - version = "6.1.6"; - }; - actionpack = { - dependencies = ["actionview" "activesupport" "rack" "rack-test" "rails-dom-testing" "rails-html-sanitizer"]; - groups = ["default" "development" "pam_authentication" "production" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1walbq04v4qvgnz39cbfhz9bzhsf14q1h7gd0kgjy3frld6ysrhb"; - type = "gem"; - }; - version = "6.1.6"; - }; - actiontext = { - dependencies = ["actionpack" "activerecord" "activestorage" "activesupport" "nokogiri"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0s6v0vnnm8zrxc3pr058r8bvgs6fxgjhadbc5r1sv1mrbyvvm1h0"; - type = "gem"; - }; - version = "6.1.6"; - }; - actionview = { - dependencies = ["activesupport" "builder" "erubi" "rails-dom-testing" "rails-html-sanitizer"]; - groups = ["default" "development" "pam_authentication" "production" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "05r0h7pvc0szqmgnra0j3j8ap7dmiyw9s6qksx41v5cxknmfi0h3"; - type = "gem"; - }; - version = "6.1.6"; - }; - active_model_serializers = { - dependencies = ["actionpack" "activemodel" "case_transform" "jsonapi-renderer"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0xdp7cpj3yj3wl4vj0nqq44kzjavlxi1wq3cf9zp0whkir0ym0gy"; - type = "gem"; - }; - version = "0.10.13"; - }; - active_record_query_trace = { - groups = ["development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "19888wjdpqvr2kaci6v6jyjw9pjf682zb1iyx2lz12mpdmy3500n"; - type = "gem"; - }; - version = "1.8"; - }; - activejob = { - dependencies = ["activesupport" "globalid"]; - groups = ["default" "development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0gjvxrzdbg0dsyqx7wsmxqfvlpl37zvzq3d1cylhb5qslsw6ml05"; - type = "gem"; - }; - version = "6.1.6"; - }; - activemodel = { - dependencies = ["activesupport"]; - groups = ["default" "development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1f0ai51icvvx5q0jd1l89k0dlwzpsrkqlj6x43f8qc4bd1ya9glx"; - type = "gem"; - }; - version = "6.1.6"; - }; - activerecord = { - dependencies = ["activemodel" "activesupport"]; - groups = ["default" "development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0khjnkvmiyap1g3rvw9hp16mzai4smqcg5hxhq28pll25ljzxdbp"; - type = "gem"; - }; - version = "6.1.6"; - }; - activestorage = { - dependencies = ["actionpack" "activejob" "activerecord" "activesupport" "marcel" "mini_mime"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "03w600j4jzgfycy2xm6cxry3q5rpvx1jvr7msy1jx65sa2shgjha"; - type = "gem"; - }; - version = "6.1.6"; - }; - activesupport = { - dependencies = ["concurrent-ruby" "i18n" "minitest" "tzinfo" "zeitwerk"]; - groups = ["default" "development" "pam_authentication" "production" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "08wzpwgdm03vzb8gqr8bvfdarb89g5ah0skvwqk6qv87p55xqkyw"; - type = "gem"; - }; - version = "6.1.6"; - }; - addressable = { - dependencies = ["public_suffix"]; - groups = ["default" "development" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "022r3m9wdxljpbya69y2i3h9g3dhhfaqzidf95m6qjzms792jvgp"; - type = "gem"; - }; - version = "2.8.0"; - }; - aes_key_wrap = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "19bn0y70qm6mfj4y1m0j3s8ggh6dvxwrwrj5vfamhdrpddsz8ddr"; - type = "gem"; - }; - version = "1.1.0"; - }; - airbrussh = { - dependencies = ["sshkit"]; - groups = ["default" "development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "16lmd6173gvhcpzj1blracx6hhlqjmmmmi4rh5y4lz6c87vg51lp"; - type = "gem"; - }; - version = "1.4.0"; - }; - android_key_attestation = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "02spc1sh7zsljl02v9d5rdb717b628vw2k7jkkplifyjk4db0zj6"; - type = "gem"; - }; - version = "0.3.0"; - }; - annotate = { - dependencies = ["activerecord" "rake"]; - groups = ["development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1lw0fxb5mirsdp3bp20gjyvs7clvi19jbxnrm2ihm20kzfhvlqcs"; - type = "gem"; - }; - version = "3.2.0"; - }; - ast = { - groups = ["default" "development" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "04nc8x27hlzlrr5c2gn7mar4vdr0apw5xg22wp6m8dx3wqr04a0y"; - type = "gem"; - }; - version = "2.4.2"; - }; - attr_encrypted = { - dependencies = ["encryptor"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0ncv2az1zlj33bsllr6q1qdvbw42gv91lxq0ryclbv8l8xh841jg"; - type = "gem"; - }; - version = "3.1.0"; - }; - attr_required = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1g22axmi2rhhy7w8c3x6gppsawxqavbrnxpnmphh22fk7cwi0kh2"; - type = "gem"; - }; - version = "1.0.1"; - }; - awrence = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "15zwdli370jfsj6jypv7vrqf4vv4ac4784faw7ar5v88fk4q9rcv"; - type = "gem"; - }; - version = "1.1.1"; - }; - aws-eventstream = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1pyis1nvnbjxk12a43xvgj2gv0mvp4cnkc1gzw0v1018r61399gz"; - type = "gem"; - }; - version = "1.2.0"; - }; - aws-partitions = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0vqb2bfq5db7x66f4n4z30c953y5q8pwwl2067nxhz6j0c486pzm"; - type = "gem"; - }; - version = "1.587.0"; - }; - aws-sdk-core = { - dependencies = ["aws-eventstream" "aws-partitions" "aws-sigv4" "jmespath"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0hajbavfngn99hcz6n20162jygvwdflldvnlrza7z32hizawaaan"; - type = "gem"; - }; - version = "3.130.2"; - }; - aws-sdk-kms = { - dependencies = ["aws-sdk-core" "aws-sigv4"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "14dcfqqdx1dy7qwrdyqdvqjs53kswm4njvg34f61jpl9xi3h2yf3"; - type = "gem"; - }; - version = "1.56.0"; - }; - aws-sdk-s3 = { - dependencies = ["aws-sdk-core" "aws-sdk-kms" "aws-sigv4"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1r6dxz3llgxbbm66jq5mkzk0i6qsxwv0d9s0ipwb23vv3bgp23yf"; - type = "gem"; - }; - version = "1.114.0"; - }; - aws-sigv4 = { - dependencies = ["aws-eventstream"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0xp7diwq7nv4vvxrl9x3lis2l4x6bissrfzbfyy6rv5bmj5w109z"; - type = "gem"; - }; - version = "1.5.0"; - }; - bcrypt = { - groups = ["default" "pam_authentication"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1rakdhrnlclrpy7sihi9ipwdh7fjkkvzga171464lq6rzp07cf65"; - type = "gem"; - }; - version = "3.1.17"; - }; - better_errors = { - dependencies = ["coderay" "erubi" "rack"]; - groups = ["development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "11220lfzhsyf5fcril3qd689kgg46qlpiiaj00hc9mh4mcbc3vrr"; - type = "gem"; - }; - version = "2.9.1"; - }; - better_html = { - dependencies = ["actionview" "activesupport" "ast" "erubi" "html_tokenizer" "parser" "smart_properties"]; - groups = ["default" "development" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1sssv94gg7bnxiqn5pbbpf8rdnmw3iyj2qwn2pbgxxs8xmmq158b"; - type = "gem"; - }; - version = "1.0.16"; - }; - bindata = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "06lqi4svq5qls9f7nnvd2zmjdqmi2sf82sq78ci5d78fq0z5x2vr"; - type = "gem"; - }; - version = "2.4.10"; - }; - binding_of_caller = { - dependencies = ["debug_inspector"]; - groups = ["development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "078n2dkpgsivcf0pr50981w95nfc2bsrp3wpf9wnxz1qsp8jbb9s"; - type = "gem"; - }; - version = "1.0.0"; - }; - blurhash = { - dependencies = ["ffi"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1rs61mwdiyriq8mb8na2sfrqzz8igls04md63ajyhk4yj8d2j0sz"; - type = "gem"; - }; - version = "0.1.6"; - }; - bootsnap = { - dependencies = ["msgpack"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0bjhh8pngmvnrsri2h6a753pgv0xdkbbgi1bmv6c7q137sp37jbg"; - type = "gem"; - }; - version = "1.11.1"; - }; - brakeman = { - groups = ["development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1m188ypcl2lb1hin21fmyk9d4fbjw4w7cr2k6l37jasw3rmgnvjv"; - type = "gem"; - }; - version = "5.2.3"; - }; - browser = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0q1yzvbqp0mykswipq3w00ljw9fgkhjfrij3hkwi7cx85r14n6gw"; - type = "gem"; - }; - version = "4.2.0"; - }; - brpoplpush-redis_script = { - dependencies = ["concurrent-ruby" "redis"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0rjm184dhlw35ymi8ifpl5155vwl6wfzdc5qjvzv634gc365yz9j"; - type = "gem"; - }; - version = "0.1.2"; - }; - builder = { - groups = ["default" "development" "pam_authentication" "production" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "045wzckxpwcqzrjr353cxnyaxgf0qg22jh00dcx7z38cys5g1jlr"; - type = "gem"; - }; - version = "3.2.4"; - }; - bullet = { - dependencies = ["activesupport" "uniform_notifier"]; - groups = ["development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0q90zk8di7a12by3d81nl78yy90rdml77vi3waxmgzqhvs6na4vj"; - type = "gem"; - }; - version = "7.0.1"; - }; - bundler-audit = { - dependencies = ["thor"]; - groups = ["development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "05k19l5388248rd74cn2lm2ksci7fzmga74n835v7k31m4kbzw8v"; - type = "gem"; - }; - version = "0.9.0.1"; - }; - byebug = { - groups = ["default" "development" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0nx3yjf4xzdgb8jkmk2344081gqr22pgjqnmjg2q64mj5d6r9194"; - type = "gem"; - }; - version = "11.1.3"; - }; - capistrano = { - dependencies = ["airbrussh" "i18n" "rake" "sshkit"]; - groups = ["development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0bbkmi746zddgrfhq0z19y053bax5l4jh8ji9mfam5aacchnz2cm"; - type = "gem"; - }; - version = "3.17.0"; - }; - capistrano-bundler = { - dependencies = ["capistrano"]; - groups = ["default" "development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "168kyi0gv2s84jm533m8rg0dii50flr06n6s2ci6kzsib3n9n8dr"; - type = "gem"; - }; - version = "2.0.1"; - }; - capistrano-rails = { - dependencies = ["capistrano" "capistrano-bundler"]; - groups = ["development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1iyhs77bff09g18dlz0li5f44khjwpqc09gk5hzcnf5v9yvijpg9"; - type = "gem"; - }; - version = "1.6.2"; - }; - capistrano-rbenv = { - dependencies = ["capistrano" "sshkit"]; - groups = ["development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1x9m1i5zd0wx122zw3m40zprlmxk9d47bd6w61k81wr4qsvkk3rw"; - type = "gem"; - }; - version = "2.2.0"; - }; - capistrano-yarn = { - dependencies = ["capistrano"]; - groups = ["development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1zdg2s061vl5b8114n909mrjb2hc1qx0i4wqx9nacsrcjgyp07l9"; - type = "gem"; - }; - version = "2.0.2"; - }; - capybara = { - dependencies = ["addressable" "matrix" "mini_mime" "nokogiri" "rack" "rack-test" "regexp_parser" "xpath"]; - groups = ["test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "05df76mfhfab6d7ir0qy5xf1ad6kqdh2p6vfqv7nhlx45k1y4ysg"; - type = "gem"; - }; - version = "3.37.1"; - }; - case_transform = { - dependencies = ["activesupport"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0fzyws6spn5arqf6q604dh9mrj84a36k5hsc8z7jgcpfvhc49bg2"; - type = "gem"; - }; - version = "0.2"; - }; - cbor = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0511idr8xps9625nh3kxr68sdy6l3xy2kcz7r57g47fxb1v18jj3"; - type = "gem"; - }; - version = "0.5.9.6"; - }; - charlock_holmes = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0hybw8jw9ryvz5zrki3gc9r88jqy373m6v46ynxsdzv1ysiyr40p"; - type = "gem"; - }; - version = "0.7.7"; - }; - chewy = { - dependencies = ["activesupport" "elasticsearch" "elasticsearch-dsl"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1jfdz0z27p839m09xmw5anrw5jp3jd5hd5gnx4vlk6kk520cy6sf"; - type = "gem"; - }; - version = "7.2.4"; - }; - chunky_png = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1znw5x86hmm9vfhidwdsijz8m38pqgmv98l9ryilvky0aldv7mc9"; - type = "gem"; - }; - version = "1.4.0"; - }; - climate_control = { - groups = ["test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0q11v0iabvr6rif0d025xh078ili5frrihlj0m04zfg7lgvagxji"; - type = "gem"; - }; - version = "0.2.0"; - }; - coderay = { - groups = ["default" "development" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0jvxqxzply1lwp7ysn94zjhh57vc14mcshw1ygw14ib8lhc00lyw"; - type = "gem"; - }; - version = "1.1.3"; - }; - color_diff = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "01dpvqlzybpb3pkcwd9ik5sbjw283618ywvdphxslhiy8ps3kp4r"; - type = "gem"; - }; - version = "0.1"; - }; - concurrent-ruby = { - groups = ["default" "development" "pam_authentication" "production" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0s4fpn3mqiizpmpy2a24k4v365pv75y50292r8ajrv4i1p5b2k14"; - type = "gem"; - }; - version = "1.1.10"; - }; - connection_pool = { - groups = ["default" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0ffdxhgirgc86qb42yvmfj6v1v0x4lvi0pxn9zhghkff44wzra0k"; - type = "gem"; - }; - version = "2.2.5"; - }; - cose = { - dependencies = ["cbor" "openssl-signature_algorithm"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1h1vcirk1vpr992xmnwf5z77fpizjwn4xzq2vrrjhvdmjynvl3jj"; - type = "gem"; - }; - version = "1.0.0"; - }; - crack = { - dependencies = ["rexml"]; - groups = ["default" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1cr1kfpw3vkhysvkk3wg7c54m75kd68mbm9rs5azdjdq57xid13r"; - type = "gem"; - }; - version = "0.4.5"; - }; - crass = { - groups = ["default" "development" "pam_authentication" "production" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0pfl5c0pyqaparxaqxi6s4gfl21bdldwiawrc0aknyvflli60lfw"; - type = "gem"; - }; - version = "1.0.6"; - }; - css_parser = { - dependencies = ["addressable"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "04c4dl8cm5rjr50k9qa6yl9r05fk9zcb1zxh0y0cdahxlsgcydfw"; - type = "gem"; - }; - version = "1.7.1"; - }; - debug_inspector = { - groups = ["default" "development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1lswmjwxf1clzaimikhiwd9s1n07qkyz7a9xwng64j4fxsajykqp"; - type = "gem"; - }; - version = "1.0.0"; - }; - devise = { - dependencies = ["bcrypt" "orm_adapter" "railties" "responders" "warden"]; - groups = ["default" "pam_authentication"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0gl0b4jqf7ysv3rg99sgxa5y9va2k13p0si3a88pr7m8g6z8pm7x"; - type = "gem"; - }; - version = "4.8.1"; - }; - devise-two-factor = { - dependencies = ["activesupport" "attr_encrypted" "devise" "railties" "rotp"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "04f5rb8fg4cvzm32v413z3h53wc0fgxg927q8rqd546hdrlx4j35"; - type = "gem"; - }; - version = "4.0.2"; - }; - devise_pam_authenticatable2 = { - dependencies = ["devise" "rpam2"]; - groups = ["pam_authentication"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "13ipl52pkhc6vxp8ca31viwv01237bi2bfk3b1fixq1x46nf87p2"; - type = "gem"; - }; - version = "9.2.0"; - }; - diff-lcs = { - groups = ["default" "development" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0rwvjahnp7cpmracd8x732rjgnilqv2sx7d1gfrysslc3h039fa9"; - type = "gem"; - }; - version = "1.5.0"; - }; - discard = { - dependencies = ["activerecord"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1xavjhccyyzn9z6fz3034vgvzprc983mbrq6n9sc0drfw7m3vrip"; - type = "gem"; - }; - version = "1.2.1"; - }; - docile = { - groups = ["default" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0wi81lynfdvbwhrc4ws746g3j8761vian4m9gxamdj9rjwj9jhls"; - type = "gem"; - }; - version = "1.3.4"; - }; - domain_name = { - dependencies = ["unf"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0lcqjsmixjp52bnlgzh4lg9ppsk52x9hpwdjd53k8jnbah2602h0"; - type = "gem"; - }; - version = "0.5.20190701"; - }; - doorkeeper = { - dependencies = ["railties"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "188ybg2cgghcp5r1jpfnbx3anf0z8fzlla72jra0vgwkdylk7qkz"; - type = "gem"; - }; - version = "5.5.4"; - }; - dotenv = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0iym172c5337sm1x2ykc2i3f961vj3wdclbyg1x6sxs3irgfsl94"; - type = "gem"; - }; - version = "2.7.6"; - }; - dotenv-rails = { - dependencies = ["dotenv" "railties"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1my2jdmgmpf32rfxffkb9cyxh7ayis4q5ygpwjqj4vpp25y3a70c"; - type = "gem"; - }; - version = "2.7.6"; - }; - ed25519 = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0zb2dr2ihb1qiknn5iaj1ha1w9p7lj9yq5waasndlfadz225ajji"; - type = "gem"; - }; - version = "1.3.0"; - }; - elasticsearch = { - dependencies = ["elasticsearch-api" "elasticsearch-transport"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0havyxmvl157a653prspnbhgdchlx44xqxl170v1im5ggxwavcaq"; - type = "gem"; - }; - version = "7.13.3"; - }; - elasticsearch-api = { - dependencies = ["multi_json"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0bmssarkk7lqkjdn8c9j7jvxcnn4hg1zcmhsky8bfvc99k33b3w8"; - type = "gem"; - }; - version = "7.13.3"; - }; - elasticsearch-dsl = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "174m3fwm3mawbkjg2xbmqvljq7ava4s95m8vpg5khcvfj506wxfk"; - type = "gem"; - }; - version = "0.1.10"; - }; - elasticsearch-transport = { - dependencies = ["faraday" "multi_json"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0blfii8qvj0m6bg9sbfynxc40in7zfmw2wpi4clv7d9gclk053db"; - type = "gem"; - }; - version = "7.13.3"; - }; - encryptor = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0s8rvfl0vn8w7k1sgkc234060jh468s3zd45xa64p1jdmfa3zwmb"; - type = "gem"; - }; - version = "3.0.0"; - }; - erubi = { - groups = ["default" "development" "pam_authentication" "production" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "09l8lz3j00m898li0yfsnb6ihc63rdvhw3k5xczna5zrjk104f2l"; - type = "gem"; - }; - version = "1.10.0"; - }; - et-orbi = { - dependencies = ["tzinfo"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1d2z4ky2v15dpcz672i2p7lb2nc793dasq3yq3660h2az53kss9v"; - type = "gem"; - }; - version = "1.2.7"; - }; - excon = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "05is0kb650j8wrdi4rgkdls662chnhdg2p64pgq3zkd3d7l2a9zw"; - type = "gem"; - }; - version = "0.76.0"; - }; - fabrication = { - groups = ["development" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0rgbmk044akxa84z9vdl8lkmd9z4xy3na1w0vh12pz02drxd93j9"; - type = "gem"; - }; - version = "2.28.0"; - }; - faker = { - dependencies = ["i18n"]; - groups = ["test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "025lapimxw0db74gf2yd6zypqq1yvfblhk7wkd6h3r1szk7k8r8p"; - type = "gem"; - }; - version = "2.21.0"; - }; - faraday = { - dependencies = ["faraday-em_http" "faraday-em_synchrony" "faraday-excon" "faraday-httpclient" "faraday-multipart" "faraday-net_http" "faraday-net_http_persistent" "faraday-patron" "faraday-rack" "faraday-retry" "ruby2_keywords"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0y32gj994ll3zlcqjmwp78r7s03iiwayij6fz2pjpkfywgvp71s6"; - type = "gem"; - }; - version = "1.9.3"; - }; - faraday-em_http = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "12cnqpbak4vhikrh2cdn94assh3yxza8rq2p9w2j34bqg5q4qgbs"; - type = "gem"; - }; - version = "1.0.0"; - }; - faraday-em_synchrony = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1vgrbhkp83sngv6k4mii9f2s9v5lmp693hylfxp2ssfc60fas3a6"; - type = "gem"; - }; - version = "1.0.0"; - }; - faraday-excon = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0h09wkb0k0bhm6dqsd47ac601qiaah8qdzjh8gvxfd376x1chmdh"; - type = "gem"; - }; - version = "1.1.0"; - }; - faraday-httpclient = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0fyk0jd3ks7fdn8nv3spnwjpzx2lmxmg2gh4inz3by1zjzqg33sc"; - type = "gem"; - }; - version = "1.0.1"; - }; - faraday-multipart = { - dependencies = ["multipart-post"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "03qfi9020ynf7hkdiaq01sd2mllvw7fg4qiin3pk028b4wv23j3j"; - type = "gem"; - }; - version = "1.0.3"; - }; - faraday-net_http = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1fi8sda5hc54v1w3mqfl5yz09nhx35kglyx72w7b8xxvdr0cwi9j"; - type = "gem"; - }; - version = "1.0.1"; - }; - faraday-net_http_persistent = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0dc36ih95qw3rlccffcb0vgxjhmipsvxhn6cw71l7ffs0f7vq30b"; - type = "gem"; - }; - version = "1.2.0"; - }; - faraday-patron = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "19wgsgfq0xkski1g7m96snv39la3zxz6x7nbdgiwhg5v82rxfb6w"; - type = "gem"; - }; - version = "1.0.0"; - }; - faraday-rack = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1h184g4vqql5jv9s9im6igy00jp6mrah2h14py6mpf9bkabfqq7g"; - type = "gem"; - }; - version = "1.0.0"; - }; - faraday-retry = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "153i967yrwnswqgvnnajgwp981k9p50ys1h80yz3q94rygs59ldd"; - type = "gem"; - }; - version = "1.0.3"; - }; - fast_blank = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1shpmamyzyhyxmv95r96ja5rylzaw60r19647d0fdm7y2h2c77r6"; - type = "gem"; - }; - version = "1.0.1"; - }; - fastimage = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0nnggg20za5vamdpkgrxxa32z33d8hf0g2bciswkhqnc6amb3yjr"; - type = "gem"; - }; - version = "2.2.6"; - }; - ffi = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1862ydmclzy1a0cjbvm8dz7847d9rch495ib0zb64y84d3xd4bkg"; - type = "gem"; - }; - version = "1.15.5"; - }; - ffi-compiler = { - dependencies = ["ffi" "rake"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0c2caqm9wqnbidcb8dj4wd3s902z15qmgxplwyfyqbwa0ydki7q1"; - type = "gem"; - }; - version = "1.0.1"; - }; - fog-core = { - dependencies = ["builder" "excon" "formatador" "mime-types"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1agd6xgzk0rxrsjdpn94v4hy89s0nm2cs4zg2p880w2dan9xgrak"; - type = "gem"; - }; - version = "2.1.0"; - }; - fog-json = { - dependencies = ["fog-core" "multi_json"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1zj8llzc119zafbmfa4ai3z5s7c4vp9akfs0f9l2piyvcarmlkyx"; - type = "gem"; - }; - version = "1.2.0"; - }; - fog-openstack = { - dependencies = ["fog-core" "fog-json" "ipaddress"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "11j18h61d3p0pcp9k5346lbj1lahab1dqybkrx9338932lmjn7ap"; - type = "gem"; - }; - version = "0.3.10"; - }; - formatador = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1gc26phrwlmlqrmz4bagq1wd5b7g64avpx0ghxr9xdxcvmlii0l0"; - type = "gem"; - }; - version = "0.2.5"; - }; - fugit = { - dependencies = ["et-orbi" "raabro"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "16xki30md6bygc62yi2s1y002vq6dm3bhjcjb9pl5dpr3al3fa1j"; - type = "gem"; - }; - version = "1.5.3"; - }; - fuubar = { - dependencies = ["rspec-core" "ruby-progressbar"]; - groups = ["development" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1028vn7j3kc5qqwswrf3has3qm4j9xva70xmzb3n29i89f0afwmj"; - type = "gem"; - }; - version = "2.5.1"; - }; - gitlab-omniauth-openid-connect = { - dependencies = ["addressable" "omniauth" "openid_connect"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1nxak6q0m0nd3m5a7vp9xqww9w5fqx97viv5g6pg3q62q9binm0j"; - type = "gem"; - }; - version = "0.9.1"; - }; - globalid = { - dependencies = ["activesupport"]; - groups = ["default" "development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1n5yc058i8xhi1fwcp1w7mfi6xaxfmrifdb4r4hjfff33ldn8lqj"; - type = "gem"; - }; - version = "1.0.0"; - }; - hamlit = { - dependencies = ["temple" "thor" "tilt"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "06imnwpzvpagwn0b9a8kwv7hncii32flmafz20z95hd77hhr6ab7"; - type = "gem"; - }; - version = "2.13.0"; - }; - hamlit-rails = { - dependencies = ["actionpack" "activesupport" "hamlit" "railties"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0v75yd6x0nwky83smd9hw5ym9h0pi32jrzbnvq55pzj0rc95gg2p"; - type = "gem"; - }; - version = "0.2.3"; - }; - hashdiff = { - groups = ["default" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1nynpl0xbj0nphqx1qlmyggq58ms1phf5i03hk64wcc0a17x1m1c"; - type = "gem"; - }; - version = "1.0.1"; - }; - hashie = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1nh3arcrbz1rc1cr59qm53sdhqm137b258y8rcb4cvd3y98lwv4x"; - type = "gem"; - }; - version = "5.0.0"; - }; - hcaptcha = { - dependencies = ["json"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0fh6391zlv2ikvzqj2gymb70k1avk1j9da8bzgw0scsz2wqq98m2"; - type = "gem"; - }; - version = "7.1.0"; - }; - highline = { - groups = ["default" "development" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0yclf57n2j3cw8144ania99h1zinf8q3f5zrhqa754j6gl95rp9d"; - type = "gem"; - }; - version = "2.0.3"; - }; - hiredis = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "04jj8k7lxqxw24sp0jiravigdkgsyrpprxpxm71ba93x1wr2w1bz"; - type = "gem"; - }; - version = "0.6.3"; - }; - hkdf = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "04fixg0a51n4vy0j6c1hvisa2yl33m3jrrpxpb5sq6j511vjriil"; - type = "gem"; - }; - version = "0.3.0"; - }; - html_tokenizer = { - groups = ["default" "development" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0dq6685sdzdn53mkzags6mvx3l0afcx6xma664zij6y3dxj2a7p8"; - type = "gem"; - }; - version = "0.0.7"; - }; - htmlentities = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1nkklqsn8ir8wizzlakncfv42i32wc0w9hxp00hvdlgjr7376nhj"; - type = "gem"; - }; - version = "4.3.4"; - }; - http = { - dependencies = ["addressable" "http-cookie" "http-form_data" "llhttp-ffi"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1akaq4wnnlbavb8rjg0vbxsg6nzbqwgkgklbmb07hix3pkp7xpxf"; - type = "gem"; - }; - version = "5.0.4"; - }; - http-cookie = { - dependencies = ["domain_name"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "19370bc97gsy2j4hanij246hv1ddc85hw0xjb6sj7n1ykqdlx9l9"; - type = "gem"; - }; - version = "1.0.4"; - }; - http-form_data = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1wx591jdhy84901pklh1n9sgh74gnvq1qyqxwchni1yrc49ynknc"; - type = "gem"; - }; - version = "2.3.0"; - }; - http_accept_language = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0d0nlfz9vm4jr1l6q0chx4rp2hrnrfbx3gadc1dz930lbbaz0hq0"; - type = "gem"; - }; - version = "2.1.1"; - }; - httpclient = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "19mxmvghp7ki3klsxwrlwr431li7hm1lczhhj8z4qihl2acy8l99"; - type = "gem"; - }; - version = "2.8.3"; - }; - httplog = { - dependencies = ["rack" "rainbow"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1dr7cj8km01kjsiwrx7n3qxr264ga13ll15s4h9dbbyj5m8kxqd2"; - type = "gem"; - }; - version = "1.5.0"; - }; - i18n = { - dependencies = ["concurrent-ruby"]; - groups = ["default" "development" "pam_authentication" "production" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0b2qyvnk4yynlg17ymkq4g5xgr275637fhl1mjh0valw3cb1fhhg"; - type = "gem"; - }; - version = "1.10.0"; - }; - i18n-tasks = { - dependencies = ["activesupport" "ast" "better_html" "erubi" "highline" "i18n" "parser" "rails-i18n" "rainbow" "terminal-table"]; - groups = ["development" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "03frq52fad0qs2gy7769nywv7bnspxccbsv10akzgx7icfjsjldv"; - type = "gem"; - }; - version = "1.0.10"; - }; - idn-ruby = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1xjr8nxpq6vsa4kd7pvd14xxiba9y4dais1yyz4dj567hsqdrhcm"; - type = "gem"; - }; - version = "0.1.4"; - }; - ipaddress = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1x86s0s11w202j6ka40jbmywkrx8fhq8xiy8mwvnkhllj57hqr45"; - type = "gem"; - }; - version = "0.8.3"; - }; - jmespath = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1mnvb80cdg7fzdcs3xscv21p28w4igk5sj5m7m81xp8v2ks87jj0"; - type = "gem"; - }; - version = "1.6.1"; - }; - json = { - groups = ["default" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0lrirj0gw420kw71bjjlqkqhqbrplla61gbv1jzgsz6bv90qr3ci"; - type = "gem"; - }; - version = "2.5.1"; - }; - json-canonicalization = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "179h6jfdsp9dmzyma7s7ykv1ia43r6z8x96j335q99p6mc5sk5qv"; - type = "gem"; - }; - version = "0.3.0"; - }; - json-jwt = { - dependencies = ["activesupport" "aes_key_wrap" "bindata"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0nzbk1mrbf9mnvjpn3bxy8a85rjf94qmfdnvk78mjzk8pa0fvgdr"; - type = "gem"; - }; - version = "1.13.0"; - }; - json-ld = { - dependencies = ["htmlentities" "json-canonicalization" "link_header" "multi_json" "rack" "rdf"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "08nll07gxgz2ys6i821nfbnsrx922d2yiqd5nd03785jjz1difbp"; - type = "gem"; - }; - version = "3.2.0"; - }; - json-ld-preloaded = { - dependencies = ["json-ld" "rdf"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0h0pfxyrsbifzhwfxj1ppaxbk7v2z8mw53a0mi49i986wyspxlgv"; - type = "gem"; - }; - version = "3.2.0"; - }; - jsonapi-renderer = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0ys4drd0k9rw5ixf8n8fx8v0pjh792w4myh0cpdspd317l1lpi5m"; - type = "gem"; - }; - version = "0.2.2"; - }; - jwt = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "14ynyq1q483spj20ffl4xayfqx1a8qr761mqjfxczf8lwlap392n"; - type = "gem"; - }; - version = "2.2.2"; - }; - kaminari = { - dependencies = ["activesupport" "kaminari-actionview" "kaminari-activerecord" "kaminari-core"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0gia8irryvfhcr6bsr64kpisbgdbqjsqfgrk12a11incmpwny1y4"; - type = "gem"; - }; - version = "1.2.2"; - }; - kaminari-actionview = { - dependencies = ["actionview" "kaminari-core"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "02f9ghl3a9b5q7l079d3yzmqjwkr4jigi7sldbps992rigygcc0k"; - type = "gem"; - }; - version = "1.2.2"; - }; - kaminari-activerecord = { - dependencies = ["activerecord" "kaminari-core"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0c148z97s1cqivzbwrak149z7kl1rdmj7dxk6rpkasimmdxsdlqd"; - type = "gem"; - }; - version = "1.2.2"; - }; - kaminari-core = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1zw3pg6kj39y7jxakbx7if59pl28lhk98fx71ks5lr3hfgn6zliv"; - type = "gem"; - }; - version = "1.2.2"; - }; - kt-paperclip = { - dependencies = ["activemodel" "activesupport" "marcel" "mime-types" "terrapin"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "08ngapld22knlkyn0dhhddkfm4vfj0lgmwj4y6x4mhi2hzfwxcxr"; - type = "gem"; - }; - version = "7.1.1"; - }; - launchy = { - dependencies = ["addressable"]; - groups = ["default" "development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1xdyvr5j0gjj7b10kgvh8ylxnwk3wx19my42wqn9h82r4p246hlm"; - type = "gem"; - }; - version = "2.5.0"; - }; - letter_opener = { - dependencies = ["launchy"]; - groups = ["development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1y5d4ip4l12v58bgazadl45iv3a5j7jp2gwg96b6jy378zn42a1d"; - type = "gem"; - }; - version = "1.8.1"; - }; - letter_opener_web = { - dependencies = ["actionmailer" "letter_opener" "railties" "rexml"]; - groups = ["development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0vvvaz2ngaxv0s6sj25gdvp73vd8pfl8q3jharadg18p3va0m1ik"; - type = "gem"; - }; - version = "2.0.0"; - }; - link_header = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1yamrdq4rywmnpdhbygnkkl9fdy249fg5r851nrkkxr97gj5rihm"; - type = "gem"; - }; - version = "0.0.8"; - }; - llhttp-ffi = { - dependencies = ["ffi-compiler" "rake"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "00dh6zmqdj59rhcya0l4b9aaxq6n8xizfbil93k0g06gndyk5xz5"; - type = "gem"; - }; - version = "0.4.0"; - }; - lograge = { - dependencies = ["actionpack" "activesupport" "railties" "request_store"]; - groups = ["production"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "15pjm9pa5m3mbv9xvfgfr16q4jyaznsg8y63jz9x4jqr8npw0vx3"; - type = "gem"; - }; - version = "0.12.0"; - }; - loofah = { - dependencies = ["crass" "nokogiri"]; - groups = ["default" "development" "pam_authentication" "production" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "18ymp6l3bv7abz07k6qbbi9c9vsiahq30d2smh4qzsvag8j5m5v1"; - type = "gem"; - }; - version = "2.18.0"; - }; - mail = { - dependencies = ["mini_mime"]; - groups = ["default" "development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "00wwz6ys0502dpk8xprwcqfwyf3hmnx6lgxaiq6vj43mkx43sapc"; - type = "gem"; - }; - version = "2.7.1"; - }; - makara = { - dependencies = ["activerecord"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0a6x6w1ij484s1z0wp667d6v0zb8bylhhr3av10yz60a2nz4r1l7"; - type = "gem"; - }; - version = "0.5.1"; - }; - marcel = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0kky3yiwagsk8gfbzn3mvl2fxlh3b39v6nawzm4wpjs6xxvvc4x0"; - type = "gem"; - }; - version = "1.0.2"; - }; - mario-redis-lock = { - dependencies = ["redis"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1v9wdjcjqzpns2migxp4a5b4w82mipi0fwihbqz3q2qj2qm7wc17"; - type = "gem"; - }; - version = "1.2.1"; - }; - matrix = { - groups = ["default" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1h2cgkpzkh3dd0flnnwfq6f3nl2b1zff9lvqz8xs853ssv5kq23i"; - type = "gem"; - }; - version = "0.4.2"; - }; - memory_profiler = { - groups = ["development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0s8qaf19yr4lhvdxk3cy3ifc47cgxdz2jybg6hzxsy9gh88c1f7v"; - type = "gem"; - }; - version = "1.0.0"; - }; - method_source = { - groups = ["default" "development" "pam_authentication" "production" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1pnyh44qycnf9mzi1j6fywd5fkskv3x7nmsqrrws0rjn5dd4ayfp"; - type = "gem"; - }; - version = "1.0.0"; - }; - microformats = { - dependencies = ["json" "nokogiri"]; - groups = ["test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "115bs94zqkgb248c7xafflpkv2vckpd0ykyfcfggj72kjpqyshyz"; - type = "gem"; - }; - version = "4.3.1"; - }; - mime-types = { - dependencies = ["mime-types-data"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0ipw892jbksbxxcrlx9g5ljq60qx47pm24ywgfbyjskbcl78pkvb"; - type = "gem"; - }; - version = "3.4.1"; - }; - mime-types-data = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "003gd7mcay800k2q4pb2zn8lwwgci4bhi42v2jvlidm8ksx03i6q"; - type = "gem"; - }; - version = "3.2022.0105"; - }; - mini_mime = { - groups = ["default" "development" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0lbim375gw2dk6383qirz13hgdmxlan0vc5da2l072j3qw6fqjm5"; - type = "gem"; - }; - version = "1.1.2"; - }; - mini_portile2 = { - groups = ["default" "development" "pam_authentication" "production" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0rapl1sfmfi3bfr68da4ca16yhc0pp93vjwkj7y3rdqrzy3b41hy"; - type = "gem"; - }; - version = "2.8.0"; - }; - minitest = { - groups = ["default" "development" "pam_authentication" "production" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "06xf558gid4w8lwx13jwfdafsch9maz8m0g85wnfymqj63x5nbbd"; - type = "gem"; - }; - version = "5.15.0"; - }; - msgpack = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1i0gbypr1yxwfkaxzrk0i1wz4n6v3mw7z24k65jy3q1h5lda5xbw"; - type = "gem"; - }; - version = "1.5.1"; - }; - multi_json = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0pb1g1y3dsiahavspyzkdy39j4q377009f6ix0bh1ag4nqw43l0z"; - type = "gem"; - }; - version = "1.15.0"; - }; - multipart-post = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1zgw9zlwh2a6i1yvhhc4a84ry1hv824d6g2iw2chs3k5aylpmpfj"; - type = "gem"; - }; - version = "2.1.1"; - }; - net-ldap = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1j19yxrz7h3hj7kiiln13c7bz7hvpdqr31bwi88dj64zifr7896n"; - type = "gem"; - }; - version = "0.17.0"; - }; - net-scp = { - dependencies = ["net-ssh"]; - groups = ["default" "development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0b4h3ip8d1gkrc0znnw54hbxillk73mdnaf5pz330lmrcl1wiilg"; - type = "gem"; - }; - version = "3.0.0"; - }; - net-ssh = { - groups = ["default" "development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0jp3jgcn8cij407xx9ldb5h9c6jv13jc4cf6kk2idclz43ww21c9"; - type = "gem"; - }; - version = "6.1.0"; - }; - nio4r = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0xk64wghkscs6bv2n22853k2nh39d131c6rfpnlw12mbjnnv9v1v"; - type = "gem"; - }; - version = "2.5.8"; - }; - nokogiri = { - dependencies = ["mini_portile2" "racc"]; - groups = ["default" "development" "pam_authentication" "production" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "11w59ga9324yx6339dgsflz3dsqq2mky1qqdwcg6wi5s1bf2yldi"; - type = "gem"; - }; - version = "1.13.6"; - }; - nsa = { - dependencies = ["activesupport" "concurrent-ruby" "sidekiq" "statsd-ruby"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1jzs1n71pi6najhs9h8jx156gzgk3h9bwjr60vazizwdz3mm69ia"; - type = "gem"; - }; - version = "0.2.8"; - }; - oj = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0bm8sdh7vz7ss3y21v961rd8nww23w5g4yhgvnd7jk331kdjyyzl"; - type = "gem"; - }; - version = "3.13.11"; - }; - omniauth = { - dependencies = ["hashie" "rack"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "002vi9gwamkmhf0dsj2im1d47xw2n1jfhnzl18shxf3ampkqfmyz"; - type = "gem"; - }; - version = "1.9.1"; - }; - omniauth-cas = { - dependencies = ["addressable" "nokogiri" "omniauth"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0kzlh1nac4yz70917cdcsk0r23gy5h7i0x5kbmkvkpbgk6gvrb0z"; - type = "gem"; - }; - version = "2.0.0"; - }; - omniauth-rails_csrf_protection = { - dependencies = ["actionpack" "omniauth"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0xgkxwg17w39q3yjqcj0fm6hdkw37qm1l82dvm9zxn6q2pbzm2zv"; - type = "gem"; - }; - version = "0.1.2"; - }; - omniauth-saml = { - dependencies = ["omniauth" "ruby-saml"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0gxl14lbksnjkl8dfn23lsjkk63md77icm5racrh6fsp5n4ni9d4"; - type = "gem"; - }; - version = "1.10.3"; - }; - openid_connect = { - dependencies = ["activemodel" "attr_required" "json-jwt" "rack-oauth2" "swd" "tzinfo" "validate_email" "validate_url" "webfinger"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0w474bz3s1hqhilvrddr33l2nkyikypaczp3808w0345jr88b5m7"; - type = "gem"; - }; - version = "1.3.0"; - }; - openssl = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "03wbynzkhay7l1x76srjkg91q48mxl575vrxb3blfxlpqwsvvp0w"; - type = "gem"; - }; - version = "2.2.0"; - }; - openssl-signature_algorithm = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "14d95jr5z6dgvpwf52p7ckjf3w3cihin2k6g9599711pfxdj4fp5"; - type = "gem"; - }; - version = "0.4.0"; - }; - orm_adapter = { - groups = ["default" "pam_authentication"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1fg9jpjlzf5y49qs9mlpdrgs5rpcyihq1s4k79nv9js0spjhnpda"; - type = "gem"; - }; - version = "0.5.0"; - }; - ox = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "054xq22rwj26jag43s5fb4vb4x2252dz6rvgjn42id8ycs51my2w"; - type = "gem"; - }; - version = "2.14.11"; - }; - parallel = { - groups = ["default" "development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "07vnk6bb54k4yc06xnwck7php50l09vvlw1ga8wdz0pia461zpzb"; - type = "gem"; - }; - version = "1.22.1"; - }; - parser = { - dependencies = ["ast"]; - groups = ["default" "development" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0xhfghgidj8cbdnqp01f7kvnrv1f60izpkd9dhxsvpdzkfsdg97d"; - type = "gem"; - }; - version = "3.1.2.0"; - }; - parslet = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "01pnw6ymz6nynklqvqxs4bcai25kcvnd5x4id9z3vd1rbmlk0lfl"; - type = "gem"; - }; - version = "2.0.0"; - }; - pastel = { - dependencies = ["tty-color"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0xash2gj08dfjvq4hy6l1z22s5v30fhizwgs10d6nviggpxsj7a8"; - type = "gem"; - }; - version = "0.8.0"; - }; - pg = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "10ryzmc3r5ja6g90a9ycsxcxsy5872xa1vf01jam0bm74zq3zmi6"; - type = "gem"; - }; - version = "1.3.5"; - }; - pghero = { - dependencies = ["activerecord"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1v0cszy9lgjqn3ax8pbj5fg01pg83wyl41wzid3g35h4xdxz1d4a"; - type = "gem"; - }; - version = "2.8.3"; - }; - pkg-config = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1rkxhps7fxzjhld68bpdaq8sss2k6fp14jz5kcqgrxp8x3yd15mk"; - type = "gem"; - }; - version = "1.4.7"; - }; - posix-spawn = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0cmb0svalqcxfzlzc5fvrci12b79x7bakasr8gkl3q5rz6di1q52"; - type = "gem"; - }; - version = "0.3.15"; - }; - premailer = { - dependencies = ["addressable" "css_parser" "htmlentities"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1f0zz3vwv1kyr43chvrpvhb8wm9qgcaz8ckc1lj2jxfp6xsss971"; - type = "gem"; - }; - version = "1.14.2"; - }; - premailer-rails = { - dependencies = ["actionmailer" "premailer"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0q23clzqgzxcg1jld7hn5jy2yqxvana3iw66vmjgzz7y4ylf97b6"; - type = "gem"; - }; - version = "1.11.1"; - }; - private_address_check = { - groups = ["production" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "05phz0vscfh9chv90yc9091pifw3cpwkh76flnhrmvja1q3na4cy"; - type = "gem"; - }; - version = "0.5.0"; - }; - pry = { - dependencies = ["coderay" "method_source"]; - groups = ["default" "development" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0iyw4q4an2wmk8v5rn2ghfy2jaz9vmw2nk8415nnpx2s866934qk"; - type = "gem"; - }; - version = "0.13.1"; - }; - pry-byebug = { - dependencies = ["byebug" "pry"]; - groups = ["development" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "096y5vmzpyy4x9h4ky4cs4y7d19vdq9vbwwrqafbh5gagzwhifiv"; - type = "gem"; - }; - version = "3.9.0"; - }; - pry-rails = { - dependencies = ["pry"]; - groups = ["development" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1cf4ii53w2hdh7fn8vhqpzkymmchjbwij4l3m7s6fsxvb9bn51j6"; - type = "gem"; - }; - version = "0.3.9"; - }; - public_suffix = { - groups = ["default" "development" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1f3knlwfwm05sfbaihrxm4g772b79032q14c16q4b38z8bi63qcb"; - type = "gem"; - }; - version = "4.0.7"; - }; - puma = { - dependencies = ["nio4r"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0dgr2rybayih2naz3658mbzqwfrg9fxl80zsvhscf6b972kp3jdw"; - type = "gem"; - }; - version = "5.6.4"; - }; - pundit = { - dependencies = ["activesupport"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "17z2f7w3syh3c04c8m1v9pvb9pfpymk8b5plszr5l24hx374xvsd"; - type = "gem"; - }; - version = "2.2.0"; - }; - raabro = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "10m8bln9d00dwzjil1k42i5r7l82x25ysbi45fwyv4932zsrzynl"; - type = "gem"; - }; - version = "1.4.0"; - }; - racc = { - groups = ["default" "development" "pam_authentication" "production" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0la56m0z26j3mfn1a9lf2l03qx1xifanndf9p3vx1azf6sqy7v9d"; - type = "gem"; - }; - version = "1.6.0"; - }; - rack = { - groups = ["default" "development" "pam_authentication" "production" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0i5vs0dph9i5jn8dfc6aqd6njcafmb20rwqngrf759c9cvmyff16"; - type = "gem"; - }; - version = "2.2.3"; - }; - rack-attack = { - dependencies = ["rack"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "049s3y3dpl6dn478g912y6f9nzclnnkl30psrbc2w5kaihj5szhq"; - type = "gem"; - }; - version = "6.6.1"; - }; - rack-cors = { - dependencies = ["rack"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0jvs0mq8jrsz86jva91mgql16daprpa3qaipzzfvngnnqr5680j7"; - type = "gem"; - }; - version = "1.1.1"; - }; - rack-oauth2 = { - dependencies = ["activesupport" "attr_required" "httpclient" "json-jwt" "rack"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0gxxr209r8h3nxhc9h731khv6yswiv9hc6q2pg672v530xmknznw"; - type = "gem"; - }; - version = "1.19.0"; - }; - rack-proxy = { - dependencies = ["rack"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0jdr2r5phr3q7d6k9cnxjwlkaps0my0n43wq9mzw3xdqhg9wa3d6"; - type = "gem"; - }; - version = "0.7.0"; - }; - rack-test = { - dependencies = ["rack"]; - groups = ["default" "development" "pam_authentication" "production" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0rh8h376mx71ci5yklnpqqn118z3bl67nnv5k801qaqn1zs62h8m"; - type = "gem"; - }; - version = "1.1.0"; - }; - rails = { - dependencies = ["actioncable" "actionmailbox" "actionmailer" "actionpack" "actiontext" "actionview" "activejob" "activemodel" "activerecord" "activestorage" "activesupport" "railties" "sprockets-rails"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "06wzq30c2f9jhsbkxwg9n18xwyh66fnpbndkrvq1c4mrl2rx478z"; - type = "gem"; - }; - version = "6.1.6"; - }; - rails-controller-testing = { - dependencies = ["actionpack" "actionview" "activesupport"]; - groups = ["test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "151f303jcvs8s149mhx2g5mn67487x0blrf9dzl76q1nb7dlh53l"; - type = "gem"; - }; - version = "1.0.5"; - }; - rails-dom-testing = { - dependencies = ["activesupport" "nokogiri"]; - groups = ["default" "development" "pam_authentication" "production" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1lfq2a7kp2x64dzzi5p4cjcbiv62vxh9lyqk2f0rqq3fkzrw8h5i"; - type = "gem"; - }; - version = "2.0.3"; - }; - rails-html-sanitizer = { - dependencies = ["loofah"]; - groups = ["default" "development" "pam_authentication" "production" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "09qrfi3pgllxb08r024lln9k0qzxs57v0slsj8616xf9c0cwnwbk"; - type = "gem"; - }; - version = "1.4.2"; - }; - rails-i18n = { - dependencies = ["i18n" "railties"]; - groups = ["default" "development" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "05mcgv748vppnm3fnml37wjy3dw61wj8vfw14ldaj1yx1bmkhb07"; - type = "gem"; - }; - version = "6.0.0"; - }; - rails-settings-cached = { - dependencies = ["rails"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0wyhyls0aqb1iw7mnaldg39w3mnbi3anmpbvb52rjwkpj2mchhnc"; - type = "gem"; - }; - version = "0.6.6"; - }; - railties = { - dependencies = ["actionpack" "activesupport" "method_source" "rake" "thor"]; - groups = ["default" "development" "pam_authentication" "production" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "16dyjmy42v51acmx1ba2xxncvx368ss5rww6bsf1lwgyk4vqn41h"; - type = "gem"; - }; - version = "6.1.6"; - }; - rainbow = { - groups = ["default" "development" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0smwg4mii0fm38pyb5fddbmrdpifwv22zv3d3px2xx497am93503"; - type = "gem"; - }; - version = "3.1.1"; - }; - rake = { - groups = ["default" "development" "pam_authentication" "production" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "15whn7p9nrkxangbs9hh75q585yfn66lv0v2mhj6q6dl6x8bzr2w"; - type = "gem"; - }; - version = "13.0.6"; - }; - rdf = { - dependencies = ["link_header"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "15bb075k614pjiw4np29y1z2xl8qx9qgdi9rpaqa1hxcmbqaxkk5"; - type = "gem"; - }; - version = "3.2.3"; - }; - rdf-normalize = { - dependencies = ["rdf"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0ysa8v2xw0ln4kdwhkg6mh71v5wbancsz5cf945kbk47m1ybn271"; - type = "gem"; - }; - version = "0.5.0"; - }; - redcarpet = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0bvk8yyns5s1ls437z719y5sdv9fr8kfs8dmr6g8s761dv5n8zvi"; - type = "gem"; - }; - version = "3.5.1"; - }; - redis = { - groups = ["default" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "03r9739q3vq38g456snf3rk9hadf955bs5im6qs6m69h19mrz2yw"; - type = "gem"; - }; - version = "4.5.1"; - }; - redis-namespace = { - dependencies = ["redis"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0ndj4lcm8rw01078zr0249grsk93zbda8qsibdvlx69b5ijg1rzf"; - type = "gem"; - }; - version = "1.8.2"; - }; - regexp_parser = { - groups = ["default" "development" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "01rmdc7ryjyajk3a4mdn68y4bvp3ly9xv610wia3291hsiqncrb6"; - type = "gem"; - }; - version = "2.4.0"; - }; - request_store = { - dependencies = ["rack"]; - groups = ["default" "production"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "13ppgmsbrqah08j06bybd3cddv6dml79yzyjn7r8j1src78h98h7"; - type = "gem"; - }; - version = "1.5.1"; - }; - responders = { - dependencies = ["actionpack" "railties"]; - groups = ["default" "pam_authentication"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "14kjykc6rpdh24sshg9savqdajya2dislc1jmbzg91w9967f4gv1"; - type = "gem"; - }; - version = "3.0.1"; - }; - rexml = { - groups = ["default" "development" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "08ximcyfjy94pm1rhcx04ny1vx2sk0x4y185gzn86yfsbzwkng53"; - type = "gem"; - }; - version = "3.2.5"; - }; - rotp = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "11q7rkjx40yi6lpylgl2jkpy162mjw7mswrcgcax86vgpbpjx6i3"; - type = "gem"; - }; - version = "6.2.0"; - }; - rpam2 = { - groups = ["default" "pam_authentication"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1zvli3s4z1hf2l7gyfickm5i3afjrnycc3ihbiax6ji6arpbyf33"; - type = "gem"; - }; - version = "4.0.2"; - }; - rqrcode = { - dependencies = ["chunky_png" "rqrcode_core"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "10sq4aknch9rzpy8af77rqxk8rr59d33slg1kwg9h7fw9f1spmjn"; - type = "gem"; - }; - version = "2.1.1"; - }; - rqrcode_core = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "06ld6386hbdhy5h0k09axmgn424kavpc8f27k1vjhknjhbf8jjfg"; - type = "gem"; - }; - version = "1.2.0"; - }; - rspec-core = { - dependencies = ["rspec-support"]; - groups = ["default" "development" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "118hkfw9b11hvvalr7qlylwal5h8dihagm9xg7k4gskg7587hca6"; - type = "gem"; - }; - version = "3.11.0"; - }; - rspec-expectations = { - dependencies = ["diff-lcs" "rspec-support"]; - groups = ["default" "development" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "001ihayil7jpfxdlxlhakvz02kx0nk5m1w0bz6z8izdx0nc8bh53"; - type = "gem"; - }; - version = "3.11.0"; - }; - rspec-mocks = { - dependencies = ["diff-lcs" "rspec-support"]; - groups = ["default" "development" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "07vagjxdm5a6s103y8zkcnja6avpl8r196hrpiffmg7sk83dqdsm"; - type = "gem"; - }; - version = "3.11.1"; - }; - rspec-rails = { - dependencies = ["actionpack" "activesupport" "railties" "rspec-core" "rspec-expectations" "rspec-mocks" "rspec-support"]; - groups = ["development" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1cqw7bhj4a4rhh1x9i5gjm9r91ckhjyngw0zcr7jw2jnfis10d7l"; - type = "gem"; - }; - version = "5.1.2"; - }; - rspec-sidekiq = { - dependencies = ["rspec-core" "sidekiq"]; - groups = ["test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1spzw3sc2p0n9qfb89y1v8igd60y7c5z9w2hjqqbbgbyjvy0agp8"; - type = "gem"; - }; - version = "3.1.0"; - }; - rspec-support = { - groups = ["default" "development" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0xfk4pla77251n39zf4n792m1rhg5sn1kp63yvpvvysany34la03"; - type = "gem"; - }; - version = "3.11.0"; - }; - rspec_junit_formatter = { - dependencies = ["rspec-core"]; - groups = ["test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1jqh5v1kjisncfzf9z0hghkaiqab086rcgy21cy3djg828sm1bxk"; - type = "gem"; - }; - version = "0.5.1"; - }; - rubocop = { - dependencies = ["parallel" "parser" "rainbow" "regexp_parser" "rexml" "rubocop-ast" "ruby-progressbar" "unicode-display_width"]; - groups = ["development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0k2wp9sxqpdyc12kp8qafls0yn44vq90zxd830s7y7rxp9xq3018"; - type = "gem"; - }; - version = "1.29.1"; - }; - rubocop-ast = { - dependencies = ["parser"]; - groups = ["default" "development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1b3p4wy68jkyq8vhm5y568wlhsihy3ilnp2c6ig18xcw1slnkypl"; - type = "gem"; - }; - version = "1.18.0"; - }; - rubocop-rails = { - dependencies = ["activesupport" "rack" "rubocop"]; - groups = ["development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "14xagb3jbms5mlcf932kx1djn2q4k952d4xia75ll36vh7xf2fpp"; - type = "gem"; - }; - version = "2.14.2"; - }; - ruby-progressbar = { - groups = ["default" "development" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "02nmaw7yx9kl7rbaan5pl8x5nn0y4j5954mzrkzi9i3dhsrps4nc"; - type = "gem"; - }; - version = "1.11.0"; - }; - ruby-saml = { - dependencies = ["nokogiri" "rexml"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1706dyk5jdma75bnl9rhmx8vgzjw12ixnj3y32inmpcgzgsvs76k"; - type = "gem"; - }; - version = "1.13.0"; - }; - ruby2_keywords = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1vz322p8n39hz3b4a9gkmz9y7a5jaz41zrm2ywf31dvkqm03glgz"; - type = "gem"; - }; - version = "0.0.5"; - }; - rufus-scheduler = { - dependencies = ["fugit"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1jvxcvsqhalndc1wh7zfdqfg78j5sx57vrgsh54pjsm1d73q79hc"; - type = "gem"; - }; - version = "3.8.1"; - }; - safety_net_attestation = { - dependencies = ["jwt"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1khq0y5w7lf2b9a220298hphf3pakd216jc9a4x4a9pdwxs2vgln"; - type = "gem"; - }; - version = "0.4.0"; - }; - sanitize = { - dependencies = ["crass" "nokogiri"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1zq8pxmsd1abw18zz6mazsm2jfpwmbgdxbpawb7bmwvkb2c5yyc1"; - type = "gem"; - }; - version = "6.0.0"; - }; - scenic = { - dependencies = ["activerecord" "railties"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0cl14f5lfidbvcx52q49xnxc4dccyrzyv38qjkda8dh07zsksw85"; - type = "gem"; - }; - version = "1.6.0"; - }; - securecompare = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0ay65wba4i7bvfqyvf5i4r48q6g70s5m724diz9gdvdavscna36b"; - type = "gem"; - }; - version = "1.0.0"; - }; - semantic_range = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1dlp97vg95plrsaaqj7x8l7z9vsjbhnqk4rw1l30gy26lmxpfrih"; - type = "gem"; - }; - version = "3.0.0"; - }; - sidekiq = { - dependencies = ["connection_pool" "rack" "redis"]; - groups = ["default" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0b06kw7frd8hrb7373pvfd39qap00ykkvipgymgwxfjzrgz0ag0d"; - type = "gem"; - }; - version = "6.4.2"; - }; - sidekiq-bulk = { - dependencies = ["sidekiq"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "08nyxzmgf742irafy3l4fj09d4s5pyvsh0dzlh8y4hl51rgkh4xv"; - type = "gem"; - }; - version = "0.2.0"; - }; - sidekiq-scheduler = { - dependencies = ["redis" "rufus-scheduler" "sidekiq" "tilt"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0kn0zzpl778345a9pc3dfc7lkgr8h1gwajs6miylmyd9krkh0yfm"; - type = "gem"; - }; - version = "4.0.0"; - }; - sidekiq-unique-jobs = { - dependencies = ["brpoplpush-redis_script" "concurrent-ruby" "sidekiq" "thor"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "170i40s7rsw66cplq2akia409vxnb8i34ypy99qpx0pxs8rp4c4d"; - type = "gem"; - }; - version = "7.1.22"; - }; - simple-navigation = { - dependencies = ["activesupport"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0izbisjc4ng77v79x6jv1z3a8fkpdb5isgjcrx60d8vl743x7hab"; - type = "gem"; - }; - version = "4.3.0"; - }; - simple_form = { - dependencies = ["actionpack" "activemodel"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "09raw1gw0db9hfddgvzjwpk4hj1ng4dfq3igak80jkvhg4jdg7jp"; - type = "gem"; - }; - version = "5.1.0"; - }; - simplecov = { - dependencies = ["docile" "simplecov-html" "simplecov_json_formatter"]; - groups = ["test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1hrv046jll6ad1s964gsmcq4hvkr3zzr6jc7z1mns22mvfpbc3cr"; - type = "gem"; - }; - version = "0.21.2"; - }; - simplecov-html = { - groups = ["default" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0yx01bxa8pbf9ip4hagqkp5m0mqfnwnw2xk8kjraiywz4lrss6jb"; - type = "gem"; - }; - version = "0.12.3"; - }; - simplecov_json_formatter = { - groups = ["default" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0cl3j7p3b5q7sxsx1va63c8imc5x6g99xablz08qrmqhpi0d6g6j"; - type = "gem"; - }; - version = "0.1.2"; - }; - smart_properties = { - groups = ["default" "development" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0jrqssk9qhwrpq41arm712226vpcr458xv6xaqbk8cp94a0kycpr"; - type = "gem"; - }; - version = "1.17.0"; - }; - sprockets = { - dependencies = ["concurrent-ruby" "rack"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "182jw5a0fbqah5w9jancvfmjbk88h8bxdbwnl4d3q809rpxdg8ay"; - type = "gem"; - }; - version = "3.7.2"; - }; - sprockets-rails = { - dependencies = ["actionpack" "activesupport" "sprockets"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1b9i14qb27zs56hlcc2hf139l0ghbqnjpmfi0054dxycaxvk5min"; - type = "gem"; - }; - version = "3.4.2"; - }; - sshkit = { - dependencies = ["net-scp" "net-ssh"]; - groups = ["default" "development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1szshiw7bzizi380z1hkdbwhjdaixb5bgbx7c3wf7970mjdashkd"; - type = "gem"; - }; - version = "1.21.2"; - }; - stackprof = { - groups = ["development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "19rnk17rz0lhf7l9awy0s7xxyw91ydcqxlx0576xvwyi79jh6a2m"; - type = "gem"; - }; - version = "0.2.19"; - }; - statsd-ruby = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "028136c463nbravckxb1qi5c5nnv9r6vh2cyhiry423lac4xz79n"; - type = "gem"; - }; - version = "1.5.0"; - }; - stoplight = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1628qf2ynldqz20h5lkaivk166qknk15gxg130n9pvz568k1sdp8"; - type = "gem"; - }; - version = "3.0.0"; - }; - strong_migrations = { - dependencies = ["activerecord"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0yk45ri2rnp00x4mdsvwdzdd9yziqxj5v9sjk74nzw0y927y3m1w"; - type = "gem"; - }; - version = "0.7.9"; - }; - swd = { - dependencies = ["activesupport" "attr_required" "httpclient"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "12b3q2sw42nnilfb51nlqdv07f31vdv2j595kd99asnkw4cjlf5w"; - type = "gem"; - }; - version = "1.3.0"; - }; - temple = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "060zzj7c2kicdfk6cpnn40n9yjnhfrr13d0rsbdhdij68chp2861"; - type = "gem"; - }; - version = "0.8.2"; - }; - terminal-table = { - dependencies = ["unicode-display_width"]; - groups = ["default" "development" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "14dfmfjppmng5hwj7c5ka6qdapawm3h6k9lhn8zj001ybypvclgr"; - type = "gem"; - }; - version = "3.0.2"; - }; - terrapin = { - dependencies = ["climate_control"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0p18f05r0c5s70571gqig3z2ym74wx79s6rd45sprp207bqskzn9"; - type = "gem"; - }; - version = "0.6.0"; - }; - thor = { - groups = ["default" "development" "pam_authentication" "production" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0inl77jh4ia03jw3iqm5ipr76ghal3hyjrd6r8zqsswwvi9j2xdi"; - type = "gem"; - }; - version = "1.2.1"; - }; - tilt = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0rn8z8hda4h41a64l0zhkiwz2vxw9b1nb70gl37h1dg2k874yrlv"; - type = "gem"; - }; - version = "2.0.10"; - }; - tpm-key_attestation = { - dependencies = ["bindata" "openssl-signature_algorithm"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1kdqyanz211wmxjzfiz2wg17gj6p4431qvjr0i6sp3d6268sssg4"; - type = "gem"; - }; - version = "0.9.0"; - }; - tty-color = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0aik4kmhwwrmkysha7qibi2nyzb4c8kp42bd5vxnf8sf7b53g73g"; - type = "gem"; - }; - version = "0.6.0"; - }; - tty-cursor = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0j5zw041jgkmn605ya1zc151bxgxl6v192v2i26qhxx7ws2l2lvr"; - type = "gem"; - }; - version = "0.7.1"; - }; - tty-prompt = { - dependencies = ["pastel" "tty-reader"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1j4y8ik82azjxshgd4i1v4wwhsv3g9cngpygxqkkz69qaa8cxnzw"; - type = "gem"; - }; - version = "0.23.1"; - }; - tty-reader = { - dependencies = ["tty-cursor" "tty-screen" "wisper"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1cf2k7w7d84hshg4kzrjvk9pkyc2g1m3nx2n1rpmdcf0hp4p4af6"; - type = "gem"; - }; - version = "0.9.0"; - }; - tty-screen = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "18jr6s1cg8yb26wzkqa6874q0z93rq0y5aw092kdqazk71y6a235"; - type = "gem"; - }; - version = "0.8.1"; - }; - twitter-text = { - dependencies = ["idn-ruby" "unf"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1dnmp0bj3l01nbb52zby2c7hrazcdwfg846knkrjdfl0yfmv793z"; - type = "gem"; - }; - version = "3.1.0"; - }; - tzinfo = { - dependencies = ["concurrent-ruby"]; - groups = ["default" "development" "pam_authentication" "production" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "10qp5x7f9hvlc0psv9gsfbxg4a7s0485wsbq1kljkxq94in91l4z"; - type = "gem"; - }; - version = "2.0.4"; - }; - tzinfo-data = { - dependencies = ["tzinfo"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0yvfyxz70r45j65763fzy0p5j8cxlhnpn1n5lcxj4is7hp8v5i23"; - type = "gem"; - }; - version = "1.2022.1"; - }; - unf = { - dependencies = ["unf_ext"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0bh2cf73i2ffh4fcpdn9ir4mhq8zi50ik0zqa1braahzadx536a9"; - type = "gem"; - }; - version = "0.1.4"; - }; - unf_ext = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0jmbimpnpjdzz8hlrppgl9spm99qh3qzbx0b81k3gkgwba8nk3yd"; - type = "gem"; - }; - version = "0.0.8"; - }; - unicode-display_width = { - groups = ["default" "development" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0csjm9shhfik0ci9mgimb7hf3xgh7nx45rkd9rzgdz6vkwr8rzxn"; - type = "gem"; - }; - version = "2.1.0"; - }; - uniform_notifier = { - groups = ["default" "development"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1614dqnky0f9f1znj0lih8i184vfps86md93dw0kxrg3af9gnqb4"; - type = "gem"; - }; - version = "1.14.2"; - }; - validate_email = { - dependencies = ["activemodel" "mail"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1r1fz29l699arka177c9xw7409d1a3ff95bf7a6pmc97slb91zlx"; - type = "gem"; - }; - version = "0.1.6"; - }; - validate_url = { - dependencies = ["activemodel" "public_suffix"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1bwj34rz7961rrl545f006m2jdz1nrc0m72gfqmnb41xwsvpagbk"; - type = "gem"; - }; - version = "1.0.13"; - }; - warden = { - dependencies = ["rack"]; - groups = ["default" "pam_authentication"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1l7gl7vms023w4clg02pm4ky9j12la2vzsixi2xrv9imbn44ys26"; - type = "gem"; - }; - version = "1.2.9"; - }; - webauthn = { - dependencies = ["android_key_attestation" "awrence" "bindata" "cbor" "cose" "openssl" "safety_net_attestation" "securecompare" "tpm-key_attestation"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1jpr8b2lzhvfxv47yjvw0h8sqa9aah5bnharh686xqzyjz9a823q"; - type = "gem"; - }; - version = "3.0.0.alpha1"; - }; - webfinger = { - dependencies = ["activesupport" "httpclient"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "18jj50b44a471ig7hw1ax90wxaaz40acmrf6cm7m2iyshlffy53q"; - type = "gem"; - }; - version = "1.2.0"; - }; - webmock = { - dependencies = ["addressable" "crack" "hashdiff"]; - groups = ["test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1l8vh8p0g92cqcvv0ra3mblsa4nczh0rz8nbwbkc3g3yzbva85xk"; - type = "gem"; - }; - version = "3.14.0"; - }; - webpacker = { - dependencies = ["activesupport" "rack-proxy" "railties" "semantic_range"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1cq6m5qwm3bmi7hkjfmbg2cs4qjq4wswlrwcfk8l1svfqbi135v3"; - type = "gem"; - }; - version = "5.4.3"; - }; - webpush = { - dependencies = ["hkdf" "jwt"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0gi7aircw2bizk08pihr9srncjy9x9iy0ymp1qgchni639k1k05s"; - type = "gem"; - }; - version = "0.3.8"; - }; - websocket-driver = { - dependencies = ["websocket-extensions"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0a3bwxd9v3ghrxzjc4vxmf4xa18c6m4xqy5wb0yk5c6b9psc7052"; - type = "gem"; - }; - version = "0.7.5"; - }; - websocket-extensions = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0hc2g9qps8lmhibl5baa91b4qx8wqw872rgwagml78ydj8qacsqw"; - type = "gem"; - }; - version = "0.1.5"; - }; - wisper = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1rpsi0ziy78cj82sbyyywby4d0aw0a5q84v65qd28vqn79fbq5yf"; - type = "gem"; - }; - version = "2.0.1"; - }; - xorcist = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1q7hr3qyn1hczv9fglqc2cbaax0fb37gjjr0y24x19mmp817csdn"; - type = "gem"; - }; - version = "1.1.2"; - }; - xpath = { - dependencies = ["nokogiri"]; - groups = ["default" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0bh8lk9hvlpn7vmi6h4hkcwjzvs2y0cmkk3yjjdr8fxvj6fsgzbd"; - type = "gem"; - }; - version = "3.2.0"; - }; - zeitwerk = { - groups = ["default" "development" "pam_authentication" "production" "test"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "09bq7j2p6mkbxnsg71s253dm2463kg51xc7bmjcxgyblqbh4ln7m"; - type = "gem"; - }; - version = "2.5.4"; - }; -} - diff --git a/packages/mastodon/source.nix b/packages/mastodon/source.nix deleted file mode 100644 index 3df79486..00000000 --- a/packages/mastodon/source.nix +++ /dev/null @@ -1,11 +0,0 @@ -# This file was generated by pkgs.mastodon.updateScript. -{ fetchgit, applyPatches }: let - src = fetchgit { - url = "https://github.com/glitch-soc/mastodon"; - rev = "c1d0a6a7981b5fe74bdd03c958a558096ea3cde8"; - sha256 = "1ybhj352wb704b2fa7vnnfzn421m03vnv5w2fy3jfikn51765bhl"; - }; -in applyPatches { - inherit src; - patches = []; -} diff --git a/packages/mastodon/update.nix b/packages/mastodon/update.nix deleted file mode 100644 index 1bd557a7..00000000 --- a/packages/mastodon/update.nix +++ /dev/null @@ -1,30 +0,0 @@ -{ pkgs -, runCommand -, lib -, makeWrapper -, yarn2nix -, bundix -, coreutils -, diffutils -, nix-prefetch-git -, gnused -, jq -}: -let - binPath = lib.makeBinPath [ yarn2nix bundix coreutils diffutils nix-prefetch-git gnused jq ]; -in -runCommand "mastodon-update-script" -{ - nativeBuildInputs = [ makeWrapper ]; - - meta = { - maintainers = with lib.maintainers; [ happy-river ]; - description = "Utility to generate Nix expressions for Mastodon's dependencies"; - platforms = lib.platforms.unix; - }; -} '' - mkdir -p $out/bin - cp ${./update.sh} $out/bin/update.sh - patchShebangs $out/bin/update.sh - wrapProgram $out/bin/update.sh --prefix PATH : ${binPath} -'' diff --git a/packages/mastodon/update.sh b/packages/mastodon/update.sh deleted file mode 100755 index 3a0686a7..00000000 --- a/packages/mastodon/update.sh +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env bash -set -e - -URL=https://github.com/mastodon/mastodon.git - -POSITIONAL=() -while [[ $# -gt 0 ]]; do - key="$1" - - case $key in - --url) - URL="$2" - shift # past argument - shift # past value - ;; - --ver) - VERSION="$2" - shift # past argument - shift # past value - ;; - --rev) - REVISION="$2" - shift # past argument - shift # past value - ;; - --patches) - PATCHES="$2" - shift # past argument - shift # past value - ;; - *) # unknown option - POSITIONAL+=("$1") - shift # past argument - ;; - esac -done - -if [[ -z "$VERSION" || -n "$POSITIONAL" ]]; then - echo "Usage: update.sh [--url URL] --ver VERSION [--rev REVISION] [--patches PATCHES]" - echo "URL may be any path acceptable to 'git clone' and VERSION the" - echo "semantic version number. If VERSION is not a revision acceptable to" - echo "'git checkout', you must provide one in REVISION. If URL is not" - echo "provided, it defaults to https://github.com/mastodon/mastodon.git." - echo "PATCHES, if provided, should be one or more Nix expressions" - echo "separated by spaces." - exit 1 -fi - -if [[ -z "$REVISION" ]]; then - REVISION="$VERSION" -fi - -rm -f gemset.nix version.nix source.nix -TARGET_DIR="$PWD" - - -WORK_DIR=$(mktemp -d) - -# Check that working directory was created. -if [[ ! "$WORK_DIR" || ! -d "$WORK_DIR" ]]; then - echo "Could not create temporary directory" - exit 1 -fi - -# Delete the working directory on exit. -function cleanup { - # Report errors, if any, from nix-prefetch-git - grep "fatal" $WORK_DIR/nix-prefetch-git.out >/dev/stderr || true - rm -rf "$WORK_DIR" -} -trap cleanup EXIT - -echo "Fetching source code $REVISION from $URL" -JSON=$(nix-prefetch-git --url "$URL" --rev "$REVISION" 2> $WORK_DIR/nix-prefetch-git.out) -SHA=$(echo $JSON | jq -r .sha256) -FETCHED_SOURCE_DIR=$(grep '^path is' $WORK_DIR/nix-prefetch-git.out | sed 's/^path is //') - -echo "Creating version.nix" -echo \"$VERSION\" | sed 's/^"v/"/' > version.nix - -cat > source.nix << EOF -# This file was generated by pkgs.mastodon.updateScript. -{ fetchgit, applyPatches }: let - src = fetchgit { - url = "$URL"; - rev = "$REVISION"; - sha256 = "$SHA"; - }; -in applyPatches { - inherit src; - patches = [$PATCHES]; -} -EOF -SOURCE_DIR="$(nix-build --no-out-link -E '(import {}).callPackage ./source.nix {}')" - -echo "Creating gemset.nix" -bundix --lockfile="$SOURCE_DIR/Gemfile.lock" --gemfile="$SOURCE_DIR/Gemfile" -echo "" >> $TARGET_DIR/gemset.nix # Create trailing newline to please EditorConfig checks diff --git a/packages/mastodon/version.nix b/packages/mastodon/version.nix deleted file mode 100644 index d23f68c2..00000000 --- a/packages/mastodon/version.nix +++ /dev/null @@ -1 +0,0 @@ -"3.5.3" diff --git a/packages/matrix/matrix-media-repo.nix b/packages/matrix/matrix-media-repo.nix deleted file mode 100644 index 081986d7..00000000 --- a/packages/matrix/matrix-media-repo.nix +++ /dev/null @@ -1,30 +0,0 @@ -{ buildGo116Module -, fetchFromGitHub -, git -}: buildGo116Module rec { - pname = "matrix-media-repo"; - version = "1.2.12"; - src = fetchFromGitHub { - owner = "turt2live"; - repo = pname; - rev = "v${version}"; - sha256 = "1j6y7alr60mmj5h014qmpz9a5qjv8cm61andwdacb0dqjjbvsm0z"; - }; - patches = [ - ./matrix-media-repo.patch - ]; - proxyVendor = true; - vendorSha256 = "sha256-gb2inc/XlPAplVYQXmR77b3/5GsEZDg5v7D/FbZRQ7w="; - nativeBuildInputs = [ - git - ]; - buildPhase = '' - GOBIN=$PWD/bin go install -v ./cmd/compile_assets - $PWD/bin/compile_assets - GOBIN=$PWD/bin go install -ldflags "-X github.com/turt2live/matrix-media-repo/common/version.GitCommit=$(git rev-list -1 HEAD) -X github.com/turt2live/matrix-media-repo/common/version.Version=$(git describe --tags)" -v ./cmd/... - ''; - installPhase = '' - mkdir $out - cp -rv bin $out - ''; -} diff --git a/packages/matrix/matrix-media-repo.patch b/packages/matrix/matrix-media-repo.patch deleted file mode 100644 index 2906f3b7..00000000 --- a/packages/matrix/matrix-media-repo.patch +++ /dev/null @@ -1,1179 +0,0 @@ -diff --git a/api/r0/download.go b/api/r0/download.go -index d84c74e..e431385 100644 ---- a/api/r0/download.go -+++ b/api/r0/download.go -@@ -48,6 +48,21 @@ func DownloadMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserI - downloadRemote = parsedFlag - } - -+ var asyncWaitMs *int = nil -+ if rctx.Config.Features.MSC2246Async.Enabled { -+ // request default wait time if feature enabled -+ var parsedInt int = -1 -+ maxStallMs := r.URL.Query().Get("fi.mau.msc2246.max_stall_ms") -+ if maxStallMs != "" { -+ var err error -+ parsedInt, err = strconv.Atoi(maxStallMs) -+ if err != nil { -+ return api.InternalServerError("fi.mau.msc2246.max_stall_ms does not appear to be a number") -+ } -+ } -+ asyncWaitMs = &parsedInt -+ } -+ - rctx = rctx.LogWithFields(logrus.Fields{ - "mediaId": mediaId, - "server": server, -@@ -55,7 +70,7 @@ func DownloadMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserI - "allowRemote": downloadRemote, - }) - -- streamedMedia, err := download_controller.GetMedia(server, mediaId, downloadRemote, false, rctx) -+ streamedMedia, err := download_controller.GetMedia(server, mediaId, downloadRemote, false, asyncWaitMs, rctx) - if err != nil { - if err == common.ErrMediaNotFound { - return api.NotFoundError() -@@ -63,6 +78,8 @@ func DownloadMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserI - return api.RequestTooLarge() - } else if err == common.ErrMediaQuarantined { - return api.NotFoundError() // We lie for security -+ } else if err == common.ErrNotYetUploaded { -+ return api.NotYetUploaded() - } - rctx.Log.Error("Unexpected error locating media: " + err.Error()) - sentry.CaptureException(err) -diff --git a/api/r0/thumbnail.go b/api/r0/thumbnail.go -index b1b73f0..8392596 100644 ---- a/api/r0/thumbnail.go -+++ b/api/r0/thumbnail.go -@@ -29,6 +29,21 @@ func ThumbnailMedia(r *http.Request, rctx rcontext.RequestContext, user api.User - downloadRemote = parsedFlag - } - -+ var asyncWaitMs *int = nil -+ if rctx.Config.Features.MSC2246Async.Enabled { -+ // request default wait time if feature enabled -+ var parsedInt int = -1 -+ maxStallMs := r.URL.Query().Get("fi.mau.msc2246.max_stall_ms") -+ if maxStallMs != "" { -+ var err error -+ parsedInt, err = strconv.Atoi(maxStallMs) -+ if err != nil { -+ return api.InternalServerError("fi.mau.msc2246.max_stall_ms does not appear to be a number") -+ } -+ } -+ asyncWaitMs = &parsedInt -+ } -+ - rctx = rctx.LogWithFields(logrus.Fields{ - "mediaId": mediaId, - "server": server, -@@ -87,12 +102,14 @@ func ThumbnailMedia(r *http.Request, rctx rcontext.RequestContext, user api.User - return api.BadRequest("Width and height must be greater than zero") - } - -- streamedThumbnail, err := thumbnail_controller.GetThumbnail(server, mediaId, width, height, animated, method, downloadRemote, rctx) -+ streamedThumbnail, err := thumbnail_controller.GetThumbnail(server, mediaId, width, height, animated, method, downloadRemote, asyncWaitMs, rctx) - if err != nil { - if err == common.ErrMediaNotFound { - return api.NotFoundError() - } else if err == common.ErrMediaTooLarge { - return api.RequestTooLarge() -+ } else if err == common.ErrNotYetUploaded { -+ return api.NotYetUploaded() - } - rctx.Log.Error("Unexpected error locating media: " + err.Error()) - sentry.CaptureException(err) -diff --git a/api/r0/upload.go b/api/r0/upload.go -index 63b0170..b47ae99 100644 ---- a/api/r0/upload.go -+++ b/api/r0/upload.go -@@ -6,7 +6,9 @@ import ( - "io/ioutil" - "net/http" - "path/filepath" -+ "time" - -+ "github.com/gorilla/mux" - "github.com/sirupsen/logrus" - "github.com/turt2live/matrix-media-repo/api" - "github.com/turt2live/matrix-media-repo/common" -@@ -14,6 +16,7 @@ import ( - "github.com/turt2live/matrix-media-repo/controllers/info_controller" - "github.com/turt2live/matrix-media-repo/controllers/upload_controller" - "github.com/turt2live/matrix-media-repo/quota" -+ "github.com/turt2live/matrix-media-repo/util" - "github.com/turt2live/matrix-media-repo/util/cleanup" - ) - -@@ -22,14 +25,52 @@ type MediaUploadedResponse struct { - Blurhash string `json:"xyz.amorgan.blurhash,omitempty"` - } - -+type MediaCreatedResponse struct { -+ ContentUri string `json:"content_uri"` -+ UnusedExpiresAt int64 `json:"unused_expires_at"` -+} -+ -+func CreateMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { -+ media, _, err := upload_controller.CreateMedia(r.Host, rctx) -+ if err != nil { -+ rctx.Log.Error("Unexpected error creating media reference: " + err.Error()) -+ return api.InternalServerError("Unexpected Error") -+ } -+ -+ if err = upload_controller.PersistMedia(media, user.UserId, rctx); err != nil { -+ rctx.Log.Error("Unexpected error persisting media reference: " + err.Error()) -+ return api.InternalServerError("Unexpected Error") -+ } -+ -+ return &MediaCreatedResponse{ -+ ContentUri: media.MxcUri(), -+ UnusedExpiresAt: time.Now().Unix() + int64(rctx.Config.Features.MSC2246Async.AsyncUploadExpirySecs), -+ } -+} -+ - func UploadMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { -+ var server = "" -+ var mediaId = "" -+ - filename := filepath.Base(r.URL.Query().Get("filename")) - defer cleanup.DumpAndCloseStream(r.Body) - -+ if rctx.Config.Features.MSC2246Async.Enabled { -+ params := mux.Vars(r) -+ server = params["server"] -+ mediaId = params["mediaId"] -+ } -+ - rctx = rctx.LogWithFields(logrus.Fields{ -+ "server": server, -+ "mediaId": mediaId, - "filename": filename, - }) - -+ if server != "" && (!util.IsServerOurs(server) || server != r.Host) { -+ return api.NotFoundError() -+ } -+ - contentType := r.Header.Get("Content-Type") - if contentType == "" { - contentType = "application/octet-stream" // binary -@@ -59,12 +100,16 @@ func UploadMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserInf - - contentLength := upload_controller.EstimateContentLength(r.ContentLength, r.Header.Get("Content-Length")) - -- media, err := upload_controller.UploadMedia(r.Body, contentLength, contentType, filename, user.UserId, r.Host, rctx) -+ media, err := upload_controller.UploadMedia(r.Body, contentLength, contentType, filename, user.UserId, r.Host, mediaId, rctx) - if err != nil { - io.Copy(ioutil.Discard, r.Body) // Ditch the entire request - - if err == common.ErrMediaQuarantined { - return api.BadRequest("This file is not permitted on this server") -+ } else if err == common.ErrCannotOverwriteMedia { -+ return api.CannotOverwriteMedia() -+ } else if err == common.ErrMediaNotFound { -+ return api.NotFoundError() - } - - rctx.Log.Error("Unexpected error storing media: " + err.Error()) -diff --git a/api/responses.go b/api/responses.go -index 93d2c39..6fd8f23 100644 ---- a/api/responses.go -+++ b/api/responses.go -@@ -57,3 +57,11 @@ func BadRequest(message string) *ErrorResponse { - func QuotaExceeded() *ErrorResponse { - return &ErrorResponse{common.ErrCodeForbidden, "Quota Exceeded", common.ErrCodeQuotaExceeded} - } -+ -+func CannotOverwriteMedia() *ErrorResponse { -+ return &ErrorResponse{common.ErrCodeCannotOverwriteMedia, "Cannot overwrite media", common.ErrCodeCannotOverwriteMedia} -+} -+ -+func NotYetUploaded() *ErrorResponse { -+ return &ErrorResponse{common.ErrCodeNotYetUploaded, "Media not yet uploaded", common.ErrCodeNotYetUploaded} -+} -diff --git a/api/unstable/info.go b/api/unstable/info.go -index 448e018..b04ff1e 100644 ---- a/api/unstable/info.go -+++ b/api/unstable/info.go -@@ -69,7 +69,7 @@ func MediaInfo(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) - "allowRemote": downloadRemote, - }) - -- streamedMedia, err := download_controller.GetMedia(server, mediaId, downloadRemote, true, rctx) -+ streamedMedia, err := download_controller.GetMedia(server, mediaId, downloadRemote, true, nil, rctx) - if err != nil { - if err == common.ErrMediaNotFound { - return api.NotFoundError() -diff --git a/api/unstable/local_copy.go b/api/unstable/local_copy.go -index 30d5f26..885633b 100644 ---- a/api/unstable/local_copy.go -+++ b/api/unstable/local_copy.go -@@ -40,7 +40,7 @@ func LocalCopy(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) - - // TODO: There's a lot of room for improvement here. Instead of re-uploading media, we should just update the DB. - -- streamedMedia, err := download_controller.GetMedia(server, mediaId, downloadRemote, true, rctx) -+ streamedMedia, err := download_controller.GetMedia(server, mediaId, downloadRemote, true, nil, rctx) - if err != nil { - if err == common.ErrMediaNotFound { - return api.NotFoundError() -@@ -60,7 +60,7 @@ func LocalCopy(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) - return &r0.MediaUploadedResponse{ContentUri: streamedMedia.KnownMedia.MxcUri()} - } - -- newMedia, err := upload_controller.UploadMedia(streamedMedia.Stream, streamedMedia.KnownMedia.SizeBytes, streamedMedia.KnownMedia.ContentType, streamedMedia.KnownMedia.UploadName, user.UserId, r.Host, rctx) -+ newMedia, err := upload_controller.UploadMedia(streamedMedia.Stream, streamedMedia.KnownMedia.SizeBytes, streamedMedia.KnownMedia.ContentType, streamedMedia.KnownMedia.UploadName, user.UserId, r.Host, "", rctx) - if err != nil { - rctx.Log.Error("Unexpected error storing media: " + err.Error()) - sentry.CaptureException(err) -diff --git a/api/webserver/route_handler.go b/api/webserver/route_handler.go -index 3d04714..a120d7a 100644 ---- a/api/webserver/route_handler.go -+++ b/api/webserver/route_handler.go -@@ -146,7 +146,7 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - case common.ErrCodeUnknownToken: - statusCode = http.StatusUnauthorized - break -- case common.ErrCodeNotFound: -+ case common.ErrCodeNotYetUploaded, common.ErrCodeNotFound: - statusCode = http.StatusNotFound - break - case common.ErrCodeMediaTooLarge: -@@ -161,6 +161,9 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - case common.ErrCodeForbidden: - statusCode = http.StatusForbidden - break -+ case common.ErrCodeCannotOverwriteMedia: -+ statusCode = http.StatusConflict -+ break - default: // Treat as unknown (a generic server error) - statusCode = http.StatusInternalServerError - break -diff --git a/api/webserver/webserver.go b/api/webserver/webserver.go -index fb9c7dd..583d270 100644 ---- a/api/webserver/webserver.go -+++ b/api/webserver/webserver.go -@@ -44,6 +44,7 @@ func Init() *sync.WaitGroup { - counter := &requestCounter{} - - optionsHandler := handler{api.EmptyResponseHandler, "options_request", counter, false} -+ createHandler := handler{api.AccessTokenRequiredRoute(r0.CreateMedia), "create", counter, false} - uploadHandler := handler{api.AccessTokenRequiredRoute(r0.UploadMedia), "upload", counter, false} - downloadHandler := handler{api.AccessTokenOptionalRoute(r0.DownloadMedia), "download", counter, false} - thumbnailHandler := handler{api.AccessTokenOptionalRoute(r0.ThumbnailMedia), "thumbnail", counter, false} -@@ -160,6 +161,12 @@ func Init() *sync.WaitGroup { - } - } - -+ if config.Get().Features.MSC2246Async.Enabled { -+ logrus.Info("Asynchronous uploads (MSC2246) enabled") -+ routes = append(routes, definedRoute{"/_matrix/media/unstable/fi.mau.msc2246/create", route{"POST", createHandler}}) -+ routes = append(routes, definedRoute{"/_matrix/media/unstable/fi.mau.msc2246/upload/{server:[a-zA-Z0-9.:\\-_]+}/{mediaId:[^/]+}", route{"PUT", uploadHandler}}) -+ } -+ - if config.Get().Features.IPFS.Enabled { - routes = append(routes, definedRoute{features.IPFSDownloadRoute, route{"GET", ipfsDownloadHandler}}) - routes = append(routes, definedRoute{features.IPFSLiveDownloadRouteR0, route{"GET", ipfsDownloadHandler}}) -diff --git a/common/config/conf_min_shared.go b/common/config/conf_min_shared.go -index e43dffc..ae0344a 100644 ---- a/common/config/conf_min_shared.go -+++ b/common/config/conf_min_shared.go -@@ -53,6 +53,11 @@ func NewDefaultMinimumRepoConfig() MinimumRepoConfig { - YComponents: 3, - Punch: 1, - }, -+ MSC2246Async: MSC2246Config{ -+ Enabled: false, -+ AsyncUploadExpirySecs: 60, -+ AsyncDownloadDefaultWaitSecs: 20, -+ }, - IPFS: IPFSConfig{ - Enabled: false, - Daemon: IPFSDaemonConfig{ -diff --git a/common/config/models_domain.go b/common/config/models_domain.go -index 3242724..c30abd9 100644 ---- a/common/config/models_domain.go -+++ b/common/config/models_domain.go -@@ -88,6 +88,7 @@ type TimeoutsConfig struct { - - type FeatureConfig struct { - MSC2448Blurhash MSC2448Config `yaml:"MSC2448"` -+ MSC2246Async MSC2246Config `yaml:"MSC2246"` - IPFS IPFSConfig `yaml:"IPFS"` - Redis RedisConfig `yaml:"redis"` - } -@@ -103,6 +104,12 @@ type MSC2448Config struct { - Punch int `yaml:"punch"` - } - -+type MSC2246Config struct { -+ Enabled bool `yaml:"enabled"` -+ AsyncUploadExpirySecs int `yaml:"asyncUploadExpirySecs"` -+ AsyncDownloadDefaultWaitSecs int `yaml:"asyncDownloadDefaultWaitSecs"` -+} -+ - type IPFSConfig struct { - Enabled bool `yaml:"enabled"` - Daemon IPFSDaemonConfig `yaml:"builtInDaemon"` -diff --git a/common/errorcodes.go b/common/errorcodes.go -index 599b32c..b9a3274 100644 ---- a/common/errorcodes.go -+++ b/common/errorcodes.go -@@ -16,3 +16,5 @@ const ErrCodeRateLimitExceeded = "M_LIMIT_EXCEEDED" - const ErrCodeUnknown = "M_UNKNOWN" - const ErrCodeForbidden = "M_FORBIDDEN" - const ErrCodeQuotaExceeded = "M_QUOTA_EXCEEDED" -+const ErrCodeCannotOverwriteMedia = "FI.MAU.MSC2246_CANNOT_OVEWRITE_MEDIA" -+const ErrCodeNotYetUploaded = "FI.MAU.MSC2246_NOT_YET_UPLOADED" -diff --git a/common/errors.go b/common/errors.go -index 5fc0e69..09f5310 100644 ---- a/common/errors.go -+++ b/common/errors.go -@@ -10,3 +10,5 @@ var ErrInvalidHost = errors.New("invalid host") - var ErrHostNotFound = errors.New("host not found") - var ErrHostBlacklisted = errors.New("host not allowed") - var ErrMediaQuarantined = errors.New("media quarantined") -+var ErrCannotOverwriteMedia = errors.New("cannot overwrite media") -+var ErrNotYetUploaded = errors.New("not yet uploaded") -diff --git a/config.sample.yaml b/config.sample.yaml -index fa49e74..0f506f1 100644 ---- a/config.sample.yaml -+++ b/config.sample.yaml -@@ -544,6 +544,20 @@ featureSupport: - # make the effect more subtle, larger values make it stronger. - punch: 1 - -+ # MSC2246 - Asynchronous uploads -+ MSC2246: -+ # Whether or not this MSC is enabled for use in the media repo -+ enabled: false -+ -+ # The number of seconds an asynchronous upload is valid to be started after requesting a media -+ # id. After expiring the upload endpoint will return an error for the client. -+ asyncUploadExpirySecs: 60 -+ -+ # The number of seconds a download request for an asynchronous upload will stall before -+ # returning an error. This affects clients that do not support async uploads by making them -+ # wait by default. Setting to zero will disable this behavior unless the client requests it. -+ asyncDownloadDefaultWaitSecs: 20 -+ - # IPFS Support - # This is currently experimental and might not work at all. - IPFS: -diff --git a/controllers/download_controller/download_controller.go b/controllers/download_controller/download_controller.go -index 4d7f354..e3d6c92 100644 ---- a/controllers/download_controller/download_controller.go -+++ b/controllers/download_controller/download_controller.go -@@ -26,14 +26,14 @@ import ( - - var localCache = cache.New(30*time.Second, 60*time.Second) - --func GetMedia(origin string, mediaId string, downloadRemote bool, blockForMedia bool, ctx rcontext.RequestContext) (*types.MinimalMedia, error) { -+func GetMedia(origin string, mediaId string, downloadRemote bool, blockForMedia bool, asyncWaitMs *int, ctx rcontext.RequestContext) (*types.MinimalMedia, error) { - cacheKey := fmt.Sprintf("%s/%s?r=%t&b=%t", origin, mediaId, downloadRemote, blockForMedia) - v, _, err := globals.DefaultRequestGroup.Do(cacheKey, func() (interface{}, error) { - var media *types.Media - var minMedia *types.MinimalMedia - var err error - if blockForMedia { -- media, err = FindMediaRecord(origin, mediaId, downloadRemote, ctx) -+ media, err = FindMediaRecord(origin, mediaId, downloadRemote, asyncWaitMs, ctx) - if media != nil { - minMedia = &types.MinimalMedia{ - Origin: media.Origin, -@@ -46,7 +46,7 @@ func GetMedia(origin string, mediaId string, downloadRemote bool, blockForMedia - } - } - } else { -- minMedia, err = FindMinimalMediaRecord(origin, mediaId, downloadRemote, ctx) -+ minMedia, err = FindMinimalMediaRecord(origin, mediaId, downloadRemote, asyncWaitMs, ctx) - if minMedia != nil { - media = minMedia.KnownMedia - } -@@ -159,7 +159,54 @@ func GetMedia(origin string, mediaId string, downloadRemote bool, blockForMedia - return value, err - } - --func FindMinimalMediaRecord(origin string, mediaId string, downloadRemote bool, ctx rcontext.RequestContext) (*types.MinimalMedia, error) { -+func waitForUpload(media *types.Media, asyncWaitMs *int, ctx rcontext.RequestContext) (*types.Media, error) { -+ if media == nil { -+ return nil, errors.New("waited for nil media") -+ } -+ -+ if util.IsServerOurs(media.Origin) && media.SizeBytes == 0 { -+ // we're not allowed to wait by requester -+ if asyncWaitMs == nil { -+ return nil, common.ErrMediaNotFound -+ } -+ -+ waitMs := *asyncWaitMs -+ -+ // max wait one minute -+ if waitMs > 60_000 { -+ waitMs = 60_000 -+ } -+ -+ // use default wait if negative -+ if waitMs < 0 { -+ waitMs = ctx.Config.Features.MSC2246Async.AsyncDownloadDefaultWaitSecs * 1000 -+ -+ // if the default is zero and client didn't request any then waiting is disabled -+ if waitMs == 0 { -+ return nil, common.ErrMediaNotFound -+ } -+ } -+ -+ // if the upload did not complete in 6 hours, consider it never will -+ if util.NowMillis()-media.CreationTs > 3600*6*1000 { -+ ctx.Log.Info("Tried to download expired asynchronous upload") -+ return nil, common.ErrMediaNotFound -+ } -+ -+ ctx.Log.Info("Asynchronous upload not complete, waiting") -+ if ok := util.WaitForUpload(media.Origin, media.MediaId, time.Millisecond*time.Duration(waitMs)); !ok { -+ return nil, common.ErrNotYetUploaded -+ } -+ -+ // fetch the entry from database again after we're notified it should be complete -+ db := storage.GetDatabase().GetMediaStore(ctx) -+ return db.Get(media.Origin, media.MediaId) -+ } -+ -+ return media, nil -+} -+ -+func FindMinimalMediaRecord(origin string, mediaId string, downloadRemote bool, asyncWaitMs *int, ctx rcontext.RequestContext) (*types.MinimalMedia, error) { - db := storage.GetDatabase().GetMediaStore(ctx) - - var media *types.Media -@@ -217,7 +264,10 @@ func FindMinimalMediaRecord(origin string, mediaId string, downloadRemote bool, - KnownMedia: nil, // unknown - }, nil - } else { -- media = dbMedia -+ media, err = waitForUpload(dbMedia, asyncWaitMs, ctx) -+ if err != nil { -+ return nil, err -+ } - } - } - -@@ -252,7 +302,7 @@ func FindMinimalMediaRecord(origin string, mediaId string, downloadRemote bool, - }, nil - } - --func FindMediaRecord(origin string, mediaId string, downloadRemote bool, ctx rcontext.RequestContext) (*types.Media, error) { -+func FindMediaRecord(origin string, mediaId string, downloadRemote bool, asyncWaitMs *int, ctx rcontext.RequestContext) (*types.Media, error) { - cacheKey := origin + "/" + mediaId - v, _, err := globals.DefaultRequestGroup.DoWithoutPost(cacheKey, func() (interface{}, error) { - db := storage.GetDatabase().GetMediaStore(ctx) -@@ -290,7 +340,10 @@ func FindMediaRecord(origin string, mediaId string, downloadRemote bool, ctx rco - } - media = result.media - } else { -- media = dbMedia -+ media, err = waitForUpload(dbMedia, asyncWaitMs, ctx) -+ if err != nil { -+ return nil, err -+ } - } - } - -diff --git a/controllers/info_controller/info_controller.go b/controllers/info_controller/info_controller.go -index 281ec60..7eee6c6 100644 ---- a/controllers/info_controller/info_controller.go -+++ b/controllers/info_controller/info_controller.go -@@ -27,7 +27,7 @@ func GetOrCalculateBlurhash(media *types.Media, rctx rcontext.RequestContext) (s - } - - rctx.Log.Info("Getting minimal media record to calculate blurhash") -- minMedia, err := download_controller.FindMinimalMediaRecord(media.Origin, media.MediaId, true, rctx) -+ minMedia, err := download_controller.FindMinimalMediaRecord(media.Origin, media.MediaId, true, nil, rctx) - if err != nil { - return "", err - } -diff --git a/controllers/maintenance_controller/maintainance_controller.go b/controllers/maintenance_controller/maintainance_controller.go -index 1df60a3..dfdd1f8 100644 ---- a/controllers/maintenance_controller/maintainance_controller.go -+++ b/controllers/maintenance_controller/maintainance_controller.go -@@ -387,7 +387,7 @@ func PurgeDomainMedia(serverName string, beforeTs int64, ctx rcontext.RequestCon - } - - func PurgeMedia(origin string, mediaId string, ctx rcontext.RequestContext) error { -- media, err := download_controller.FindMediaRecord(origin, mediaId, false, ctx) -+ media, err := download_controller.FindMediaRecord(origin, mediaId, false, nil, ctx) - if err != nil { - return err - } -diff --git a/controllers/preview_controller/preview_resource_handler.go b/controllers/preview_controller/preview_resource_handler.go -index 86c42b9..cd99dba 100644 ---- a/controllers/preview_controller/preview_resource_handler.go -+++ b/controllers/preview_controller/preview_resource_handler.go -@@ -133,7 +133,7 @@ func urlPreviewWorkFn(request *resource_handler.WorkRequest) (resp *urlPreviewRe - contentLength := upload_controller.EstimateContentLength(preview.Image.ContentLength, preview.Image.ContentLengthHeader) - - // UploadMedia will close the read stream for the thumbnail and dedupe the image -- media, err := upload_controller.UploadMedia(preview.Image.Data, contentLength, preview.Image.ContentType, preview.Image.Filename, info.forUserId, info.onHost, ctx) -+ media, err := upload_controller.UploadMedia(preview.Image.Data, contentLength, preview.Image.ContentType, preview.Image.Filename, info.forUserId, info.onHost, "", ctx) - if err != nil { - ctx.Log.Warn("Non-fatal error storing preview thumbnail: " + err.Error()) - sentry.CaptureException(err) -diff --git a/controllers/thumbnail_controller/thumbnail_controller.go b/controllers/thumbnail_controller/thumbnail_controller.go -index 9b5e121..c464790 100644 ---- a/controllers/thumbnail_controller/thumbnail_controller.go -+++ b/controllers/thumbnail_controller/thumbnail_controller.go -@@ -26,8 +26,8 @@ import ( - - var localCache = cache.New(30*time.Second, 60*time.Second) - --func GetThumbnail(origin string, mediaId string, desiredWidth int, desiredHeight int, animated bool, method string, downloadRemote bool, ctx rcontext.RequestContext) (*types.StreamedThumbnail, error) { -- media, err := download_controller.FindMediaRecord(origin, mediaId, downloadRemote, ctx) -+func GetThumbnail(origin string, mediaId string, desiredWidth int, desiredHeight int, animated bool, method string, downloadRemote bool, asyncWaitMs *int, ctx rcontext.RequestContext) (*types.StreamedThumbnail, error) { -+ media, err := download_controller.FindMediaRecord(origin, mediaId, downloadRemote, asyncWaitMs, ctx) - if err != nil { - return nil, err - } -diff --git a/controllers/upload_controller/upload_controller.go b/controllers/upload_controller/upload_controller.go -index 7936faa..25759ff 100644 ---- a/controllers/upload_controller/upload_controller.go -+++ b/controllers/upload_controller/upload_controller.go -@@ -1,6 +1,7 @@ - package upload_controller - - import ( -+ "database/sql" - "fmt" - "github.com/getsentry/sentry-go" - "io" -@@ -92,39 +93,26 @@ func EstimateContentLength(contentLength int64, contentLengthHeader string) int6 - return -1 // unknown - } - --func UploadMedia(contents io.ReadCloser, contentLength int64, contentType string, filename string, userId string, origin string, ctx rcontext.RequestContext) (*types.Media, error) { -- defer cleanup.DumpAndCloseStream(contents) -- -- var data io.ReadCloser -- if ctx.Config.Uploads.MaxSizeBytes > 0 { -- data = ioutil.NopCloser(io.LimitReader(contents, ctx.Config.Uploads.MaxSizeBytes)) -- } else { -- data = contents -- } -- -- dataBytes, err := ioutil.ReadAll(data) -- if err != nil { -- return nil, err -- } -- -+func CreateMedia(origin string, ctx rcontext.RequestContext) (*types.Media, *datastore.DatastoreRef, error) { - metadataDb := storage.GetDatabase().GetMetadataStore(ctx) - - mediaTaken := true - var mediaId string -+ var err error - attempts := 0 - for mediaTaken { - attempts += 1 - if attempts > 10 { -- return nil, errors.New("failed to generate a media ID after 10 rounds") -+ return nil, nil, errors.New("failed to generate a media ID after 10 rounds") - } - - mediaId, err = util.GenerateRandomString(64) - if err != nil { -- return nil, err -+ return nil, nil, err - } - mediaId, err = util.GetSha1OfString(mediaId + strconv.FormatInt(util.NowMillis(), 10)) - if err != nil { -- return nil, err -+ return nil, nil, err - } - - // Because we use the current time in the media ID, we don't need to worry about -@@ -136,17 +124,88 @@ func UploadMedia(contents io.ReadCloser, contentLength int64, contentType string - - mediaTaken, err = metadataDb.IsReserved(origin, mediaId) - if err != nil { -- return nil, err -+ return nil, nil, err - } - } - - _ = recentMediaIds.Add(mediaId, true, cache.DefaultExpiration) - -- var existingFile *AlreadyUploadedFile = nil - ds, err := datastore.PickDatastore(common.KindLocalMedia, ctx) -+ if err != nil { -+ return nil, nil, err -+ } -+ -+ return &types.Media{MediaId: mediaId, Origin: origin, DatastoreId: ds.DatastoreId}, ds, nil -+} -+ -+func PersistMedia(media *types.Media, userId string, ctx rcontext.RequestContext) error { -+ db := storage.GetDatabase().GetMediaStore(ctx) -+ -+ ctx.Log.Info("Persisting async media record") -+ -+ media.UserId = userId -+ media.CreationTs = util.NowMillis() -+ -+ return db.Insert(media) -+} -+ -+func UploadMedia(contents io.ReadCloser, contentLength int64, contentType string, filename string, userId string, origin string, asyncMediaId string, ctx rcontext.RequestContext) (*types.Media, error) { -+ defer cleanup.DumpAndCloseStream(contents) -+ -+ var data io.ReadCloser -+ if ctx.Config.Uploads.MaxSizeBytes > 0 { -+ data = ioutil.NopCloser(io.LimitReader(contents, ctx.Config.Uploads.MaxSizeBytes)) -+ } else { -+ data = contents -+ } -+ -+ dataBytes, err := ioutil.ReadAll(data) - if err != nil { - return nil, err - } -+ -+ var mediaId string -+ var ds *datastore.DatastoreRef -+ if asyncMediaId == "" { -+ media, newDs, err := CreateMedia(origin, ctx) -+ if err != nil { -+ return nil, err -+ } -+ -+ mediaId = media.MediaId -+ ds = newDs -+ } else { -+ db := storage.GetDatabase().GetMediaStore(ctx) -+ -+ media, err := db.Get(origin, asyncMediaId) -+ if err != nil { -+ return nil, err -+ } -+ -+ if media == nil { -+ return nil, common.ErrMediaNotFound -+ } -+ -+ if media.UserId != userId { -+ return nil, common.ErrMediaNotFound -+ } -+ -+ if media.SizeBytes > 0 { -+ return nil, common.ErrCannotOverwriteMedia -+ } -+ -+ if util.NowMillis()-media.CreationTs > int64(ctx.Config.Features.MSC2246Async.AsyncUploadExpirySecs*1000) { -+ return nil, common.ErrMediaNotFound -+ } -+ -+ mediaId = asyncMediaId -+ ds, err = datastore.LocateDatastore(ctx, media.DatastoreId) -+ if err != nil { -+ return nil, err -+ } -+ } -+ -+ var existingFile *AlreadyUploadedFile = nil - if ds.Type == "ipfs" { - // Do the upload now so we can pick the media ID to point to IPFS - info, err := ds.UploadFile(util_byte_seeker.NewByteSeeker(dataBytes), contentLength, ctx) -@@ -160,15 +219,22 @@ func UploadMedia(contents io.ReadCloser, contentLength int64, contentType string - mediaId = fmt.Sprintf("ipfs:%s", info.Location[len("ipfs/"):]) - } - -- m, err := StoreDirect(existingFile, util_byte_seeker.NewByteSeeker(dataBytes), contentLength, contentType, filename, userId, origin, mediaId, common.KindLocalMedia, ctx, true) -+ m, err := StoreDirect(existingFile, util_byte_seeker.NewByteSeeker(dataBytes), contentLength, contentType, filename, userId, origin, mediaId, common.KindLocalMedia, ctx, asyncMediaId == "") - if err != nil { - return m, err - } - if m != nil { -- err = internal_cache.Get().UploadMedia(m.Sha256Hash, util_byte_seeker.NewByteSeeker(dataBytes), ctx) -- if err != nil { -+ util.NotifyUpload(origin, mediaId) -+ -+ cache := internal_cache.Get() -+ if err := cache.UploadMedia(m.Sha256Hash, util_byte_seeker.NewByteSeeker(dataBytes), ctx); err != nil { - ctx.Log.Warn("Unexpected error trying to cache media: " + err.Error()) - } -+ if asyncMediaId != "" { -+ if err := cache.NotifyUpload(origin, mediaId, ctx); err != nil { -+ ctx.Log.Warn("Unexpected error trying to notify cache about media: " + err.Error()) -+ } -+ } - } - return m, err - } -@@ -193,8 +259,7 @@ func checkSpam(contents []byte, filename string, contentType string, userId stri - return nil - } - --func StoreDirect(f *AlreadyUploadedFile, contents io.ReadCloser, expectedSize int64, contentType string, filename string, userId string, origin string, mediaId string, kind string, ctx rcontext.RequestContext, filterUserDuplicates bool) (*types.Media, error) { -- var err error -+func StoreDirect(f *AlreadyUploadedFile, contents io.ReadCloser, expectedSize int64, contentType string, filename string, userId string, origin string, mediaId string, kind string, ctx rcontext.RequestContext, filterUserDuplicates bool) (ret *types.Media, err error) { - var ds *datastore.DatastoreRef - var info *types.ObjectInfo - var contentBytes []byte -@@ -229,15 +294,16 @@ func StoreDirect(f *AlreadyUploadedFile, contents io.ReadCloser, expectedSize in - return nil, err - } - } -+ defer func() { -+ // always delete temp object if we return an error -+ if err != nil { -+ ds.DeleteObject(info.Location) -+ } -+ }() - - db := storage.GetDatabase().GetMediaStore(ctx) - records, err := db.GetByHash(info.Sha256Hash) - if err != nil { -- err2 := ds.DeleteObject(info.Location) // delete temp object -- if err2 != nil { -- ctx.Log.Warn("Error deleting temporary upload", err2) -- sentry.CaptureException(err2) -- } - return nil, err - } - -@@ -270,22 +336,12 @@ func StoreDirect(f *AlreadyUploadedFile, contents io.ReadCloser, expectedSize in - - err = checkSpam(contentBytes, filename, contentType, userId, origin, mediaId) - if err != nil { -- err2 := ds.DeleteObject(info.Location) // delete temp object -- if err2 != nil { -- ctx.Log.Warn("Error deleting temporary upload", err2) -- sentry.CaptureException(err2) -- } - return nil, err - } - - // We'll use the location from the first record - record := records[0] - if record.Quarantined { -- err2 := ds.DeleteObject(info.Location) // delete temp object -- if err2 != nil { -- ctx.Log.Warn("Error deleting temporary upload", err2) -- sentry.CaptureException(err2) -- } - ctx.Log.Warn("User attempted to upload quarantined content - rejecting") - return nil, common.ErrMediaQuarantined - } -@@ -304,21 +360,37 @@ func StoreDirect(f *AlreadyUploadedFile, contents io.ReadCloser, expectedSize in - } - } - -- media := record -- media.Origin = origin -- media.MediaId = mediaId -- media.UserId = userId -- media.UploadName = filename -- media.ContentType = contentType -- media.CreationTs = util.NowMillis() -+ // Check if we have reserved the metadata already -+ media, err := db.Get(origin, mediaId) -+ if err == sql.ErrNoRows { -+ media = record -+ media.Origin = origin -+ media.MediaId = mediaId -+ media.UserId = userId -+ media.UploadName = filename -+ media.ContentType = contentType -+ media.CreationTs = util.NowMillis() -+ -+ if err = db.Insert(media); err != nil { -+ return nil, err -+ } -+ } else if err == nil { -+ // last minute check if the file was already uploaded -+ if media.SizeBytes > 0 { -+ return nil, common.ErrCannotOverwriteMedia -+ } - -- err = db.Insert(media) -- if err != nil { -- err2 := ds.DeleteObject(info.Location) // delete temp object -- if err2 != nil { -- ctx.Log.Warn("Error deleting temporary upload", err2) -- sentry.CaptureException(err2) -+ media.UploadName = filename -+ media.ContentType = contentType -+ media.Sha256Hash = info.Sha256Hash -+ media.SizeBytes = info.SizeBytes -+ media.DatastoreId = ds.DatastoreId -+ media.Location = info.Location -+ -+ if err = db.Update(media); err != nil { -+ return nil, err - } -+ } else { - return nil, err - } - -@@ -327,11 +399,6 @@ func StoreDirect(f *AlreadyUploadedFile, contents io.ReadCloser, expectedSize in - if media.DatastoreId != ds.DatastoreId && media.Location != info.Location { - ds2, err := datastore.LocateDatastore(ctx, media.DatastoreId) - if err != nil { -- err2 := ds.DeleteObject(info.Location) // delete temp object -- if err2 != nil { -- ctx.Log.Warn("Error deleting temporary upload", err2) -- sentry.CaptureException(err2) -- } - return nil, err - } - if !ds2.ObjectExists(media.Location) { -@@ -366,46 +433,54 @@ func StoreDirect(f *AlreadyUploadedFile, contents io.ReadCloser, expectedSize in - // The media doesn't already exist - save it as new - - if info.SizeBytes <= 0 { -- err2 := ds.DeleteObject(info.Location) // delete temp object -- if err2 != nil { -- ctx.Log.Warn("Error deleting temporary upload", err2) -- sentry.CaptureException(err2) -- } - return nil, errors.New("file has no contents") - } - - err = checkSpam(contentBytes, filename, contentType, userId, origin, mediaId) - if err != nil { -- err2 := ds.DeleteObject(info.Location) // delete temp object -- if err2 != nil { -- ctx.Log.Warn("Error deleting temporary upload", err2) -- sentry.CaptureException(err2) -- } - return nil, err - } - -- ctx.Log.Info("Persisting new media record") -- -- media := &types.Media{ -- Origin: origin, -- MediaId: mediaId, -- UploadName: filename, -- ContentType: contentType, -- UserId: userId, -- Sha256Hash: info.Sha256Hash, -- SizeBytes: info.SizeBytes, -- DatastoreId: ds.DatastoreId, -- Location: info.Location, -- CreationTs: util.NowMillis(), -- } -+ // Check if we have reserved the metadata already, validate uploader -+ media, err := db.Get(origin, mediaId) -+ if err == sql.ErrNoRows { -+ ctx.Log.Info("Persisting new media record") -+ -+ media = &types.Media{ -+ Origin: origin, -+ MediaId: mediaId, -+ UploadName: filename, -+ ContentType: contentType, -+ UserId: userId, -+ Sha256Hash: info.Sha256Hash, -+ SizeBytes: info.SizeBytes, -+ DatastoreId: ds.DatastoreId, -+ Location: info.Location, -+ CreationTs: util.NowMillis(), -+ } - -- err = db.Insert(media) -- if err != nil { -- err2 := ds.DeleteObject(info.Location) // delete temp object -- if err2 != nil { -- ctx.Log.Warn("Error deleting temporary upload", err2) -- sentry.CaptureException(err2) -+ if err = db.Insert(media); err != nil { -+ return nil, err - } -+ } else if err == nil { -+ ctx.Log.Info("Updating existing media record") -+ -+ // last minute check if the file was already uploaded -+ if media.SizeBytes > 0 { -+ return nil, common.ErrCannotOverwriteMedia -+ } -+ -+ media.UploadName = filename -+ media.ContentType = contentType -+ media.Sha256Hash = info.Sha256Hash -+ media.SizeBytes = info.SizeBytes -+ media.DatastoreId = ds.DatastoreId -+ media.Location = info.Location -+ -+ if err = db.Update(media); err != nil { -+ return nil, err -+ } -+ } else { - return nil, err - } - -diff --git a/internal_cache/cache.go b/internal_cache/cache.go -index b871a07..0b0a5af 100644 ---- a/internal_cache/cache.go -+++ b/internal_cache/cache.go -@@ -18,4 +18,5 @@ type ContentCache interface { - MarkDownload(fileHash string) - GetMedia(sha256hash string, contents FetchFunction, ctx rcontext.RequestContext) (*CachedContent, error) - UploadMedia(sha256hash string, content io.ReadCloser, ctx rcontext.RequestContext) error -+ NotifyUpload(origin string, mediaId string, ctx rcontext.RequestContext) error - } -diff --git a/internal_cache/noop.go b/internal_cache/noop.go -index 8a4f936..9d4a264 100644 ---- a/internal_cache/noop.go -+++ b/internal_cache/noop.go -@@ -35,3 +35,8 @@ func (n *NoopCache) UploadMedia(sha256hash string, content io.ReadCloser, ctx rc - // do nothing - return nil - } -+ -+func (n *NoopCache) NotifyUpload(origin string, mediaId string, ctx rcontext.RequestContext) error { -+ // do nothing -+ return nil -+} -diff --git a/internal_cache/redis.go b/internal_cache/redis.go -index aeb4c2c..baacab0 100644 ---- a/internal_cache/redis.go -+++ b/internal_cache/redis.go -@@ -67,3 +67,7 @@ func (c *RedisCache) UploadMedia(sha256hash string, content io.ReadCloser, ctx r - defer content.Close() - return c.redis.SetStream(ctx, sha256hash, content) - } -+ -+func (c *RedisCache) NotifyUpload(origin string, mediaId string, ctx rcontext.RequestContext) error { -+ return c.redis.NotifyUpload(ctx, origin, mediaId) -+} -diff --git a/redis_cache/redis.go b/redis_cache/redis.go -index c129490..13a6434 100644 ---- a/redis_cache/redis.go -+++ b/redis_cache/redis.go -@@ -12,6 +12,8 @@ import ( - "github.com/sirupsen/logrus" - "github.com/turt2live/matrix-media-repo/common/config" - "github.com/turt2live/matrix-media-repo/common/rcontext" -+ "github.com/turt2live/matrix-media-repo/types" -+ "github.com/turt2live/matrix-media-repo/util" - ) - - var ErrCacheMiss = errors.New("missed cache") -@@ -32,14 +34,45 @@ func NewCache(conf config.RedisConfig) *RedisCache { - DB: conf.DbNum, - }) - -+ ctx := context.Background() -+ - logrus.Info("Contacting Redis shards...") -- _ = ring.ForEachShard(context.Background(), func(ctx context.Context, client *redis.Client) error { -+ _ = ring.ForEachShard(ctx, func(ctx context.Context, client *redis.Client) error { - logrus.Infof("Pinging %s", client.String()) - r, err := client.Ping(ctx).Result() - if err != nil { - return err - } - logrus.Infof("%s replied with: %s", client.String(), r) -+ -+ psub := client.Subscribe(ctx, "upload") -+ go func() { -+ logrus.Infof("Client %s going to subscribe to uploads", client.String()) -+ for { -+ for { -+ msg, err := psub.ReceiveMessage(ctx) -+ if err != nil { -+ break -+ } -+ -+ ref := types.MediaRef{} -+ if err := ref.UnmarshalBinary([]byte(msg.Payload)); err != nil { -+ logrus.Warn("Failed to unmarshal published upload, ignoring") -+ continue -+ } -+ -+ logrus.Infof("Client %s notified about %s/%s being uploaded", client.String(), ref.Origin, ref.MediaId) -+ util.NotifyUpload(ref.Origin, ref.MediaId) -+ } -+ -+ if ctx.Done() != nil { -+ return -+ } -+ -+ time.Sleep(time.Second * 1) -+ } -+ }() -+ - return nil - }) - -@@ -97,3 +130,21 @@ func (c *RedisCache) GetBytes(ctx rcontext.RequestContext, key string) ([]byte, - b, err := r.Bytes() - return b, err - } -+ -+func (c *RedisCache) NotifyUpload(ctx rcontext.RequestContext, origin string, mediaId string) error { -+ if c.ring.PoolStats().TotalConns == 0 { -+ return ErrCacheDown -+ } -+ r := c.ring.Publish(ctx, "upload", types.MediaRef{Origin: origin, MediaId: mediaId}) -+ if r.Err() != nil { -+ if r.Err() == redis.Nil { -+ return ErrCacheMiss -+ } -+ if c.ring.PoolStats().TotalConns == 0 { -+ ctx.Log.Error(r.Err()) -+ return ErrCacheDown -+ } -+ return r.Err() -+ } -+ return nil -+} -diff --git a/storage/stores/media_store.go b/storage/stores/media_store.go -index 958f1b0..71aaa3a 100644 ---- a/storage/stores/media_store.go -+++ b/storage/stores/media_store.go -@@ -16,6 +16,7 @@ import ( - const selectMedia = "SELECT origin, media_id, upload_name, content_type, user_id, sha256_hash, size_bytes, datastore_id, location, creation_ts, quarantined FROM media WHERE origin = $1 and media_id = $2;" - const selectMediaByHash = "SELECT origin, media_id, upload_name, content_type, user_id, sha256_hash, size_bytes, datastore_id, location, creation_ts, quarantined FROM media WHERE sha256_hash = $1;" - const insertMedia = "INSERT INTO media (origin, media_id, upload_name, content_type, user_id, sha256_hash, size_bytes, datastore_id, location, creation_ts, quarantined) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11);" -+const updateMedia = "UPDATE media SET upload_name = $3, content_type = $4, sha256_hash = $5, size_bytes = $6, datastore_id = $7, location = $8 WHERE origin = $1 AND media_id = $2;" - const selectOldMedia = "SELECT m.origin, m.media_id, m.upload_name, m.content_type, m.user_id, m.sha256_hash, m.size_bytes, m.datastore_id, m.location, m.creation_ts, quarantined FROM media AS m WHERE m.origin <> ANY($1) AND m.creation_ts < $2 AND (SELECT COUNT(*) FROM media AS d WHERE d.sha256_hash = m.sha256_hash AND d.creation_ts >= $2) = 0 AND (SELECT COUNT(*) FROM media AS d WHERE d.sha256_hash = m.sha256_hash AND d.origin = ANY($1)) = 0;" - const selectOrigins = "SELECT DISTINCT origin FROM media;" - const deleteMedia = "DELETE FROM media WHERE origin = $1 AND media_id = $2;" -@@ -47,6 +48,7 @@ type mediaStoreStatements struct { - selectMedia *sql.Stmt - selectMediaByHash *sql.Stmt - insertMedia *sql.Stmt -+ updateMedia *sql.Stmt - selectOldMedia *sql.Stmt - selectOrigins *sql.Stmt - deleteMedia *sql.Stmt -@@ -97,6 +99,9 @@ func InitMediaStore(sqlDb *sql.DB) (*MediaStoreFactory, error) { - if store.stmts.insertMedia, err = store.sqlDb.Prepare(insertMedia); err != nil { - return nil, err - } -+ if store.stmts.updateMedia, err = store.sqlDb.Prepare(updateMedia); err != nil { -+ return nil, err -+ } - if store.stmts.selectOldMedia, err = store.sqlDb.Prepare(selectOldMedia); err != nil { - return nil, err - } -@@ -190,6 +195,22 @@ func (s *MediaStore) Insert(media *types.Media) error { - return err - } - -+func (s *MediaStore) Update(media *types.Media) error { -+ _, err := s.statements.updateMedia.ExecContext( -+ s.ctx, -+ media.Origin, -+ media.MediaId, -+ media.UploadName, -+ media.ContentType, -+ media.Sha256Hash, -+ media.SizeBytes, -+ media.DatastoreId, -+ media.Location, -+ ) -+ -+ return err -+} -+ - func (s *MediaStore) GetByHash(hash string) ([]*types.Media, error) { - rows, err := s.statements.selectMediaByHash.QueryContext(s.ctx, hash) - if err != nil { -diff --git a/types/media.go b/types/media.go -index 873da95..9172ae2 100644 ---- a/types/media.go -+++ b/types/media.go -@@ -1,6 +1,22 @@ - package types - --import "io" -+import ( -+ "encoding/json" -+ "io" -+) -+ -+type MediaRef struct { -+ Origin string -+ MediaId string -+} -+ -+func (ref MediaRef) MarshalBinary() ([]byte, error) { -+ return json.Marshal(ref) -+} -+ -+func (ref *MediaRef) UnmarshalBinary(data []byte) error { -+ return json.Unmarshal(data, ref) -+} - - type Media struct { - Origin string -diff --git a/util/upload_notifier.go b/util/upload_notifier.go -new file mode 100644 -index 0000000..84a9bd4 ---- /dev/null -+++ b/util/upload_notifier.go -@@ -0,0 +1,61 @@ -+package util -+ -+import ( -+ "sync" -+ "time" -+) -+ -+type mediaSet map[chan struct{}]struct{} -+ -+var waiterLock = &sync.Mutex{} -+var waiters = map[string]mediaSet{} -+ -+func WaitForUpload(origin string, mediaId string, timeout time.Duration) bool { -+ key := origin + mediaId -+ ch := make(chan struct{}, 1) -+ -+ waiterLock.Lock() -+ var set mediaSet -+ var ok bool -+ if set, ok = waiters[key]; !ok { -+ set = make(mediaSet) -+ waiters[key] = set -+ } -+ set[ch] = struct{}{} -+ waiterLock.Unlock() -+ -+ defer func() { -+ waiterLock.Lock() -+ -+ delete(set, ch) -+ close(ch) -+ -+ if len(set) == 0 { -+ delete(waiters, key) -+ } -+ -+ waiterLock.Unlock() -+ }() -+ -+ select { -+ case <-ch: -+ return true -+ case <-time.After(timeout): -+ return false -+ } -+} -+ -+func NotifyUpload(origin string, mediaId string) { -+ waiterLock.Lock() -+ defer waiterLock.Unlock() -+ -+ set := waiters[origin+mediaId] -+ -+ if set == nil { -+ return -+ } -+ -+ for channel := range set { -+ channel <- struct{}{} -+ } -+} diff --git a/packages/matrix/mautrix-whatsapp.nix b/packages/matrix/mautrix-whatsapp.nix deleted file mode 100644 index 1e1f8519..00000000 --- a/packages/matrix/mautrix-whatsapp.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ buildGo118Module -, fetchFromGitHub -, olm -}: buildGo118Module rec { - pname = "mautrix-whatsapp"; - version = "0.4.0"; - src = fetchFromGitHub { - owner = "mautrix"; - repo = "whatsapp"; - rev = "v${version}"; - sha256 = "sha256-2F0smK2L9Xj3/65j7vwwGT1OLxcTqkImpn16wB5rWDw="; - }; - proxyVendor = true; - vendorSha256 = "sha256-CuLlg7lynJNNkGhZEh+Un6Mx3whhcU4hHF0rCggo6h4="; - buildInputs = [ olm ]; -} diff --git a/packages/miifox.nix b/packages/miifox.nix deleted file mode 100644 index 1d6853e4..00000000 --- a/packages/miifox.nix +++ /dev/null @@ -1,17 +0,0 @@ -miifox-net: { lndir, stdenvNoCC, python3Packages, ... }: stdenvNoCC.mkDerivation { - name = "miifox.net"; - srcs = miifox-net; - nativeBuildInputs = [ - python3Packages.chevron - lndir - ]; - buildPhase = '' - chevron -d index.json index.handlebars > index.html - ''; - installPhase = '' - mkdir $out - lndir -silent ${miifox-net} $out - cp index.html $out - rm $out/index.json - ''; -} diff --git a/packages/minecraft/paper.nix b/packages/minecraft/paper.nix deleted file mode 100644 index 346b7d4d..00000000 --- a/packages/minecraft/paper.nix +++ /dev/null @@ -1,37 +0,0 @@ -{ lib, stdenv, fetchurl, bash, openjdk17_headless }: -let - mcVersion = "1.18.2"; - buildNum = "332"; - jar = fetchurl { - url = "https://papermc.io/api/v2/projects/paper/versions/${mcVersion}/builds/${buildNum}/downloads/paper-${mcVersion}-${buildNum}.jar"; - sha256 = "333f4a7d1d2048d222dc5a02e5c26871905f980ab6a7f394153b0818ebada49e"; - }; -in -stdenv.mkDerivation { - pname = "papermc"; - version = "${mcVersion}r${buildNum}"; - - preferLocalBuild = true; - - dontUnpack = true; - dontConfigure = true; - - buildPhase = '' - cat > minecraft-server << EOF - #!${bash}/bin/sh - exec ${openjdk17_headless}/bin/java \$@ -jar $out/share/papermc/papermc.jar nogui - ''; - - installPhase = '' - install -Dm444 ${jar} $out/share/papermc/papermc.jar - install -Dm555 -t $out/bin minecraft-server - ''; - - meta = { - description = "High-performance Minecraft Server"; - homepage = "https://papermc.io/"; - license = lib.licenses.gpl3Only; - platforms = lib.platforms.unix; - maintainers = with lib.maintainers; [ aaronjanse neonfuz ]; - }; -} diff --git a/packages/old-homepage.nix b/packages/old-homepage.nix deleted file mode 100644 index 0710a2bd..00000000 --- a/packages/old-homepage.nix +++ /dev/null @@ -1,6 +0,0 @@ -{ ... }: { - homepage-old = builtins.fetchTarball { - url = "https://static.darkkirb.de/homepage.tar.zst"; - sha256 = "1wf90kpb0ra0fy0msh1drmr4jjxw7c1q3ksqc9zfy04sjh6y5msg"; - }; -}