diff --git a/.env.example b/.env.example index 752fcad..ff29e4f 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,9 @@ NODE_ID=aUniqueString +DATABASE_URL=ecto://chessh:password@database/chessh + +POSTGRES_USER=chessh +POSTGRES_PASSWORD=password +POSTGRES_DATABASE=chessh REACT_APP_GITHUB_OAUTH=https://github.com/login/oauth/authorize?client_id=CLIENT_ID_HERE&redirect_uri=http://127.0.0.1:3000/api/oauth/redirect CLIENT_REDIRECT_AFTER_OAUTH=http://127.0.0.1:3000/auth-successful @@ -12,3 +17,6 @@ JWT_SECRET=aVerySecretJwtSigningSecret SSH_PORT=42069 REACT_APP_SSH_SERVER=localhost REACT_APP_SSH_PORT=42069 + +REDIS_HOST=localhost +REDIS_PORT=6379 diff --git a/Dockerfile b/Dockerfile index 80fd412..6ef0845 100644 --- a/Dockerfile +++ b/Dockerfile @@ -49,7 +49,7 @@ RUN mix release # the compiled release and other runtime necessities FROM ${RUNNER_IMAGE} -RUN apt-get update -y && apt-get install -y libstdc++6 openssl libncurses5 locales \ +RUN apt-get update -y && apt-get install -y libstdc++6 openssl libncurses5 locales redis \ && apt-get clean && rm -f /var/lib/apt/lists/*_* # Set the locale @@ -69,7 +69,8 @@ ENV MIX_ENV="prod" COPY --from=builder --chown=nobody:root /app/_build/${MIX_ENV}/rel/chessh ./ COPY --from=builder --chown=nobody:root /app/priv /app/priv -USER nobody +# USER nobody +USER root EXPOSE 8080 EXPOSE 34355 diff --git a/config/config.exs b/config/config.exs index ef3c828..15cde18 100644 --- a/config/config.exs +++ b/config/config.exs @@ -1,9 +1,5 @@ import Config -# This will be redis when scaled across multiple nodes -config :hammer, - backend: {Hammer.Backend.ETS, [expiry_ms: 60_000 * 60 * 4, cleanup_interval_ms: 60_000 * 10]} - config :chessh, ecto_repos: [Chessh.Repo], key_dir: Path.join(Path.dirname(__DIR__), "priv/keys"), diff --git a/config/runtime.exs b/config/runtime.exs index 5c741ff..f3cc03c 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -1,5 +1,20 @@ import Config +config :hammer, + backend: [ + in_memory: + {Hammer.Backend.ETS, [expiry_ms: 60_000 * 60 * 4, cleanup_interval_ms: 60_000 * 10]}, + redis: + {Hammer.Backend.Redis, + [ + expiry_ms: 60_000 * 60 * 2, + redix_config: [ + host: System.get_env("REDIS_HOST", "localhost"), + port: String.to_integer(System.get_env("REDIS_PORT", "6379")) + ] + ]} + ] + config :chessh, port: String.to_integer(System.get_env("SSH_PORT", "42069")) diff --git a/deploy.sh b/deploy.sh index 51d49cf..63104a4 100755 --- a/deploy.sh +++ b/deploy.sh @@ -7,7 +7,7 @@ port=8080 ssh_port=34355 host=0.0.0.0 -container_names=("chessh-database" "chessh-server" "chessh-frontend") +container_names=("chessh-redis" "chessh-database" "chessh-server" "chessh-frontend") for name in ${container_names[@]}; do docker stop $name @@ -17,41 +17,55 @@ done # Create network for chessh docker network ls | grep -q $project_name || docker network create --driver bridge $project_name +# Create redis volume if it does not exist +docker volume ls | grep -q $project_name-redisdata || docker volume create $project_name-redisdata + +# Then start the redis container +docker run \ + -d \ + --restart unless-stopped \ + --env-file $env_file \ + --network $project_name \ + --name $project_name-redis \ + --net-alias redis \ + --volume $project_name-redisdata:/data/ \ + redis + # Start postgres container # Firstly create pg volume if it does not exist docker volume ls | grep -q $project_name-pgdata || docker volume create $project_name-pgdata # Then run the pg container docker run \ - -d \ - --restart unless-stopped \ - --env-file $env_file \ - --network $project_name \ - --name $project_name-database \ - --net-alias database \ - --volume $project_name-pgdata:/var/lib/postgresql/data/ \ - postgres + -d \ + --restart unless-stopped \ + --env-file $env_file \ + --network $project_name \ + --name $project_name-database \ + --net-alias database \ + --volume $project_name-pgdata:/var/lib/postgresql/data/ \ + postgres # Start backend container # Check if running; if so, stop, and rename docker run \ - -d \ - --restart unless-stopped \ - --env-file $env_file \ - --network $project_name \ - --name $project_name-server \ + -d \ + --restart unless-stopped \ + --env-file $env_file \ + --network $project_name \ + --name $project_name-server \ --publish "${host}:${ssh_port}:${ssh_port}/tcp" \ - --net-alias server \ + --net-alias server \ chessh/server # Start frontend container # Check if running; if so, stop, and rename docker run \ - -d \ - --restart unless-stopped \ - --env-file $env_file \ - --network $project_name \ - --name $project_name-frontend \ + -d \ + --restart unless-stopped \ + --env-file $env_file \ + --network $project_name \ + --name $project_name-frontend \ --publish "${host}:${port}:80/tcp" \ - --net-alias frontend \ + --net-alias frontend \ chessh/frontend diff --git a/lib/chessh/ssh/client/client.ex b/lib/chessh/ssh/client/client.ex index 381f337..2554d64 100644 --- a/lib/chessh/ssh/client/client.ex +++ b/lib/chessh/ssh/client/client.ex @@ -76,6 +76,7 @@ defmodule Chessh.SSH.Client do |> Keyword.values() case Hammer.check_rate_inc( + :in_memory, "player-session-#{state.player_session.id}-burst-message-rate", burst_ms, burst_rate, diff --git a/lib/chessh/ssh/daemon.ex b/lib/chessh/ssh/daemon.ex index 6be6732..d602781 100644 --- a/lib/chessh/ssh/daemon.ex +++ b/lib/chessh/ssh/daemon.ex @@ -37,7 +37,7 @@ defmodule Chessh.SSH.Daemon do "#{username} on bucket #{rateId} got their password wrong, or they don't exist! Point at them and laugh!!!!" ) - case Hammer.check_rate_inc(rateId, jail_timeout_ms, jail_attempt_threshold, 1) do + case Hammer.check_rate_inc(:redis, rateId, jail_timeout_ms, jail_attempt_threshold, 1) do {:allow, _count} -> Logger.debug("Bucket #{rateId} can continue to brute force though") false diff --git a/mix.exs b/mix.exs index 586120e..8c89083 100644 --- a/mix.exs +++ b/mix.exs @@ -33,6 +33,7 @@ defmodule Chessh.MixProject do {:postgrex, "~> 0.16.5"}, {:bcrypt_elixir, "~> 3.0"}, {:hammer, "~> 6.1"}, + {:hammer_backend_redis, "~> 6.1"}, {:syn, "~> 3.3"}, {:jason, "~> 1.3"}, {:plug_cowboy, "~> 2.2"}, diff --git a/mix.lock b/mix.lock index d5b54b8..73438d2 100644 --- a/mix.lock +++ b/mix.lock @@ -15,6 +15,7 @@ "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, "esshd": {:hex, :esshd, "0.2.1", "cded6a329c32bc3b3c15828bcd34203227bbef310db3c39a6f3c55cf5b29cd34", [:mix], [], "hexpm", "b058b56af53aba1c23522d72a3c39ab7f302e509af1c0ba1a748f00d93053c4d"}, "hammer": {:hex, :hammer, "6.1.0", "f263e3c3e9946bd410ea0336b2abe0cb6260af4afb3a221e1027540706e76c55", [:make, :mix], [{:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}], "hexpm", "b47e415a562a6d072392deabcd58090d8a41182cf9044cdd6b0d0faaaf68ba57"}, + "hammer_backend_redis": {:hex, :hammer_backend_redis, "6.1.2", "eb296bb4924928e24135308b2afc189201fd09411c870c6bbadea444a49b2f2c", [:mix], [{:hammer, "~> 6.0", [hex: :hammer, repo: "hexpm", optional: false]}, {:redix, "~> 1.1", [hex: :redix, repo: "hexpm", optional: false]}], "hexpm", "217ea066278910543a5e9b577d5bf2425419446b94fe76bdd9f255f39feec9fa"}, "jason": {:hex, :jason, "1.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"}, "joken": {:hex, :joken, "2.5.0", "09be497d804b8115eb6f07615cef2e60c2a1008fb89dc0aef0d4c4b4609b99aa", [:mix], [{:jose, "~> 1.11.2", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "22b25c89617c5ed8ca7b31026340a25ea0f9ca7160f9706b79be9ed81fdf74e7"}, "jose": {:hex, :jose, "1.11.5", "3bc2d75ffa5e2c941ca93e5696b54978323191988eb8d225c2e663ddfefd515e", [:mix, :rebar3], [], "hexpm", "dcd3b215bafe02ea7c5b23dafd3eb8062a5cd8f2d904fd9caa323d37034ab384"}, @@ -25,6 +26,7 @@ "poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"}, "postgrex": {:hex, :postgrex, "0.16.5", "fcc4035cc90e23933c5d69a9cd686e329469446ef7abba2cf70f08e2c4b69810", [:mix], [{:connection, "~> 1.1", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "edead639dc6e882618c01d8fc891214c481ab9a3788dfe38dd5e37fd1d5fb2e8"}, "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, + "redix": {:hex, :redix, "1.2.0", "0d7eb3ccb7b82c461a6ea28b65c2c04486093d816dd6d901a09164800e004df1", [:mix], [{:castore, "~> 0.1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e1e0deb14599da07c77e66956a12863e85ee270ada826804a0ba8e61657e22a3"}, "syn": {:hex, :syn, "3.3.0", "4684a909efdfea35ce75a9662fc523e4a8a4e8169a3df275e4de4fa63f99c486", [:rebar3], [], "hexpm", "e58ee447bc1094bdd21bf0acc102b1fbf99541a508cd48060bf783c245eaf7d6"}, "telemetry": {:hex, :telemetry, "1.1.0", "a589817034a27eab11144ad24d5c0f9fab1f58173274b1e9bae7074af9cbee51", [:rebar3], [], "hexpm", "b727b2a1f75614774cff2d7565b64d0dfa5bd52ba517f16543e6fc7efcc0df48"}, "ueberauth": {:hex, :ueberauth, "0.10.3", "4a3bd7ab7b5d93d301d264f0f6858392654ee92171f4437d067d1ae227c051d9", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "1394f36a6c64e97f2038cf95228e7e52b4cb75417962e30418fbe9902b30e6d3"},