Better logging, close previous sessions once session threshold has been reached
This commit is contained in:
parent
58d0b1a89c
commit
52a3ed7c57
@ -34,7 +34,7 @@ defmodule Chessh.PlayerSession do
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def player_within_concurrent_sessions_and_satisfies(username, auth_fn) do
|
def update_sessions_and_player_satisfies(username, auth_fn) do
|
||||||
max_sessions =
|
max_sessions =
|
||||||
Application.get_env(:chessh, RateLimits)
|
Application.get_env(:chessh, RateLimits)
|
||||||
|> Keyword.get(:max_concurrent_user_sessions)
|
|> Keyword.get(:max_concurrent_user_sessions)
|
||||||
@ -51,9 +51,7 @@ defmodule Chessh.PlayerSession do
|
|||||||
send(self(), {:authed, false})
|
send(self(), {:authed, false})
|
||||||
|
|
||||||
player ->
|
player ->
|
||||||
authed =
|
authed = auth_fn.(player)
|
||||||
auth_fn.(player) &&
|
|
||||||
PlayerSession.concurrent_sessions(player) < max_sessions
|
|
||||||
|
|
||||||
if authed do
|
if authed do
|
||||||
Logger.debug(
|
Logger.debug(
|
||||||
@ -67,6 +65,29 @@ defmodule Chessh.PlayerSession do
|
|||||||
process: Utils.pid_to_str(self())
|
process: Utils.pid_to_str(self())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
concurrent_sessions = PlayerSession.concurrent_sessions(player)
|
||||||
|
|
||||||
|
if concurrent_sessions > max_sessions do
|
||||||
|
expired_sessions =
|
||||||
|
Repo.all(
|
||||||
|
from(p in PlayerSession,
|
||||||
|
select: p.id,
|
||||||
|
order_by: [asc: :login],
|
||||||
|
limit: ^(concurrent_sessions - max_sessions)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
Logger.debug(
|
||||||
|
"Player #{player.username} has #{length(expired_sessions)} expired sessions - attempting to close them"
|
||||||
|
)
|
||||||
|
|
||||||
|
Enum.map(expired_sessions, fn session_id ->
|
||||||
|
:syn.publish(:player_sessions, {:session, session_id}, :session_closed)
|
||||||
|
end)
|
||||||
|
|
||||||
|
Repo.delete_all(from(p in PlayerSession, where: p.id in ^expired_sessions))
|
||||||
|
end
|
||||||
|
|
||||||
player
|
player
|
||||||
|> Player.authentications_changeset(%{authentications: player.authentications + 1})
|
|> Player.authentications_changeset(%{authentications: player.authentications + 1})
|
||||||
|> Repo.update()
|
|> Repo.update()
|
||||||
|
@ -1,16 +1,27 @@
|
|||||||
defmodule Chessh.SSH.Client do
|
defmodule Chessh.SSH.Client do
|
||||||
alias Chessh.SSH.Client
|
alias IO.ANSI
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
use GenServer
|
use GenServer
|
||||||
|
|
||||||
# TODO: tui_state_stack is like [:menu, :player_settings, :change_password] or [:menu, {:game, game_id}, {:game_chat, game_id}]
|
@default_message [
|
||||||
|
ANSI.clear(),
|
||||||
|
ANSI.reset(),
|
||||||
|
ANSI.home(),
|
||||||
|
["Hello, world"]
|
||||||
|
]
|
||||||
|
|
||||||
defstruct [:tui_pid, :width, :height, :player_id, :tui_state_stack]
|
defmodule State do
|
||||||
|
defstruct tui_pid: nil,
|
||||||
|
width: nil,
|
||||||
|
height: nil,
|
||||||
|
player_session: nil,
|
||||||
|
state_statck: []
|
||||||
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def init([tui_pid, width, height] = args) do
|
def init([%State{tui_pid: tui_pid} = state]) do
|
||||||
Logger.debug("#{inspect(args)}")
|
send(tui_pid, {:send_data, @default_message})
|
||||||
{:ok, %Client{tui_pid: tui_pid, width: width, height: height}}
|
{:ok, state}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
defmodule Chessh.SSH.Daemon do
|
defmodule Chessh.SSH.Daemon do
|
||||||
alias Chessh.{Repo, PlayerSession, Utils}
|
alias Chessh.{Repo, PlayerSession, Utils}
|
||||||
alias Chessh.Auth.PasswordAuthenticator
|
alias Chessh.Auth.PasswordAuthenticator
|
||||||
|
alias Chessh.SSH.{ServerKey, Tui}
|
||||||
|
|
||||||
use GenServer
|
use GenServer
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
|
||||||
@ -30,24 +32,30 @@ defmodule Chessh.SSH.Daemon do
|
|||||||
String.Chars.to_string(password)
|
String.Chars.to_string(password)
|
||||||
) do
|
) do
|
||||||
false ->
|
false ->
|
||||||
|
Logger.debug(
|
||||||
|
"#{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(rateId, jail_timeout_ms, jail_attempt_threshold, 1) do
|
||||||
{:allow, _count} ->
|
{:allow, _count} ->
|
||||||
|
Logger.debug("Bucket #{rateId} can continue to brute force though")
|
||||||
false
|
false
|
||||||
|
|
||||||
{:deny, _limit} ->
|
{:deny, _limit} ->
|
||||||
|
Logger.debug("Bucket #{rateId} ran out of password attempts")
|
||||||
:disconnect
|
:disconnect
|
||||||
end
|
end
|
||||||
|
|
||||||
x ->
|
x ->
|
||||||
if PlayerSession.player_within_concurrent_sessions_and_satisfies(username, fn _player ->
|
PlayerSession.update_sessions_and_player_satisfies(username, fn _player ->
|
||||||
|
x
|
||||||
|
end)
|
||||||
|
|
||||||
x
|
x
|
||||||
end),
|
|
||||||
do: true,
|
|
||||||
else: :disconnect
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def pwd_authenticate(username, password, inet, _address),
|
def pwd_authenticate(username, password, inet, _state),
|
||||||
do: pwd_authenticate(username, password, inet)
|
do: pwd_authenticate(username, password, inet)
|
||||||
|
|
||||||
def handle_cast(:start, state) do
|
def handle_cast(:start, state) do
|
||||||
@ -57,19 +65,19 @@ defmodule Chessh.SSH.Daemon do
|
|||||||
|
|
||||||
case :ssh.daemon(
|
case :ssh.daemon(
|
||||||
port,
|
port,
|
||||||
# shell: fn _username, _peer -> Process.sleep(5000) end,
|
|
||||||
system_dir: key_dir,
|
system_dir: key_dir,
|
||||||
pwdfun: &pwd_authenticate/4,
|
pwdfun: &pwd_authenticate/4,
|
||||||
key_cb: Chessh.SSH.ServerKey,
|
key_cb: ServerKey,
|
||||||
ssh_cli: {Chessh.SSH.Tui, []},
|
ssh_cli: {Tui, [%Tui.State{}]},
|
||||||
# connectfun: &on_connect/3,
|
|
||||||
disconnectfun: &on_disconnect/1,
|
disconnectfun: &on_disconnect/1,
|
||||||
id_string: :random,
|
id_string: :random,
|
||||||
subsystems: [],
|
|
||||||
parallel_login: true,
|
parallel_login: true,
|
||||||
max_sessions: max_sessions
|
max_sessions: max_sessions,
|
||||||
|
subsystems: []
|
||||||
) do
|
) do
|
||||||
{:ok, pid} ->
|
{:ok, pid} ->
|
||||||
|
Logger.info("SSH server started on port #{port}, on #{inspect(pid)}")
|
||||||
|
|
||||||
Process.link(pid)
|
Process.link(pid)
|
||||||
{:noreply, %{state | pid: pid}, :hibernate}
|
{:noreply, %{state | pid: pid}, :hibernate}
|
||||||
|
|
||||||
|
@ -5,9 +5,9 @@ defmodule Chessh.SSH.ServerKey do
|
|||||||
@behaviour :ssh_server_key_api
|
@behaviour :ssh_server_key_api
|
||||||
|
|
||||||
def is_auth_key(key, username, _daemon_options) do
|
def is_auth_key(key, username, _daemon_options) do
|
||||||
PlayerSession.player_within_concurrent_sessions_and_satisfies(
|
PlayerSession.update_sessions_and_player_satisfies(
|
||||||
username,
|
username,
|
||||||
&KeyAuthenticator.authenticate(&1, key)
|
fn player -> KeyAuthenticator.authenticate(player, key) end
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1,45 +1,90 @@
|
|||||||
defmodule Chessh.SSH.Tui do
|
defmodule Chessh.SSH.Tui do
|
||||||
|
alias Chessh.{Repo, PlayerSession, Utils, Player}
|
||||||
|
alias Chessh.SSH.Client
|
||||||
|
|
||||||
|
alias IO.ANSI
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
@behaviour :ssh_server_channel
|
@behaviour :ssh_server_channel
|
||||||
|
@session_closed_message [
|
||||||
|
ANSI.clear(),
|
||||||
|
["This session has been closed"]
|
||||||
|
]
|
||||||
|
|
||||||
def init(opts) do
|
defmodule State do
|
||||||
Logger.debug("#{inspect(opts)}")
|
defstruct channel_id: nil,
|
||||||
|
width: nil,
|
||||||
|
height: nil,
|
||||||
|
client_pid: nil,
|
||||||
|
connection_ref: nil,
|
||||||
|
player_session: nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def init([%State{} = init_state]) do
|
||||||
|
:syn.add_node_to_scopes([:player_sessions])
|
||||||
|
{:ok, init_state}
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle_msg({:ssh_channel_up, channel_id, connection_ref}, state) do
|
||||||
|
Logger.debug("SSH channel up #{inspect(:ssh.connection_info(connection_ref))}")
|
||||||
|
|
||||||
|
connected_player =
|
||||||
|
:ssh.connection_info(connection_ref)
|
||||||
|
|> Keyword.fetch!(:user)
|
||||||
|
|> String.Chars.to_string()
|
||||||
|
|
||||||
|
case Repo.get_by(Player, username: connected_player) do
|
||||||
|
nil ->
|
||||||
|
Logger.error("Killing channel #{channel_id} - auth'd user does not exist")
|
||||||
|
{:stop, channel_id, state}
|
||||||
|
|
||||||
|
player ->
|
||||||
|
case Repo.get_by(PlayerSession,
|
||||||
|
node_id: System.fetch_env!("NODE_ID"),
|
||||||
|
process: Utils.pid_to_str(connection_ref),
|
||||||
|
player_id: player.id
|
||||||
|
) do
|
||||||
|
nil ->
|
||||||
|
Logger.error("Killing channel #{channel_id} - session does not exist")
|
||||||
|
{:stop, channel_id, state}
|
||||||
|
|
||||||
|
session ->
|
||||||
|
Logger.debug("Subscribing to session #{session.id}")
|
||||||
|
:syn.join(:player_sessions, {:session, session.id}, self())
|
||||||
|
|
||||||
{:ok,
|
{:ok,
|
||||||
%{
|
%{
|
||||||
channel: nil,
|
state
|
||||||
cm: nil,
|
| channel_id: channel_id,
|
||||||
pty: %{term: nil, width: nil, height: nil, pixwidth: nil, pixheight: nil, modes: nil},
|
connection_ref: connection_ref,
|
||||||
shell: false,
|
player_session: session
|
||||||
client_pid: nil
|
|
||||||
}}
|
}}
|
||||||
end
|
end
|
||||||
|
end
|
||||||
@spec handle_msg(any, any) ::
|
|
||||||
:ok
|
|
||||||
| {:ok, atom | %{:channel => any, :cm => any, optional(any) => any}}
|
|
||||||
| {:stop, any, %{:channel => any, :client_pid => any, optional(any) => any}}
|
|
||||||
def handle_msg({:ssh_channel_up, channel_id, connection_handler}, state) do
|
|
||||||
Logger.debug(
|
|
||||||
"SSH CHANNEL UP #{inspect(connection_handler)} #{inspect(:ssh.connection_info(connection_handler))}"
|
|
||||||
)
|
|
||||||
|
|
||||||
{:ok, %{state | channel: channel_id, cm: connection_handler}}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_msg({:EXIT, client_pid, _reason}, %{client_pid: client_pid} = state) do
|
def handle_msg({:EXIT, client_pid, _reason}, %{client_pid: client_pid} = state) do
|
||||||
{:stop, state.channel, state}
|
{:stop, state.channel, state}
|
||||||
end
|
end
|
||||||
|
|
||||||
### commands we expect from the client ###
|
def handle_msg(
|
||||||
def handle_msg({:send_data, data}, state) do
|
{:send_data, data},
|
||||||
Logger.debug("DATA SENT #{inspect(data)}")
|
%{connection_ref: connection_ref, channel_id: channel_id} = state
|
||||||
:ssh_connection.send(state.cm, state.channel, data)
|
) do
|
||||||
|
Logger.debug("Data was sent to TUI process #{inspect(data)}")
|
||||||
|
:ssh_connection.send(connection_ref, channel_id, data)
|
||||||
{:ok, state}
|
{:ok, state}
|
||||||
end
|
end
|
||||||
|
|
||||||
### catch all for what we haven't seen ###
|
def handle_msg(
|
||||||
|
:session_closed,
|
||||||
|
%{connection_ref: connection_ref, channel_id: channel_id} = state
|
||||||
|
) do
|
||||||
|
:ssh_connection.send(connection_ref, channel_id, @session_closed_message)
|
||||||
|
{:stop, channel_id, state}
|
||||||
|
end
|
||||||
|
|
||||||
def handle_msg(msg, term) do
|
def handle_msg(msg, term) do
|
||||||
Logger.debug("Unknown msg #{inspect(msg)}, #{inspect(term)}")
|
Logger.debug("Unknown msg #{inspect(msg)}, #{inspect(term)}")
|
||||||
end
|
end
|
||||||
@ -49,28 +94,23 @@ defmodule Chessh.SSH.Tui do
|
|||||||
state
|
state
|
||||||
) do
|
) do
|
||||||
Logger.debug("DATA #{inspect(data)}")
|
Logger.debug("DATA #{inspect(data)}")
|
||||||
send(state.client_pid, {:data, data})
|
# send(state.client_pid, {:data, data})
|
||||||
{:ok, state}
|
{:ok, state}
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_ssh_msg(
|
def handle_ssh_msg(
|
||||||
{:ssh_cm, connection_handler,
|
{:ssh_cm, connection_handler,
|
||||||
{:pty, channel_id, want_reply?, {term, width, height, pixwidth, pixheight, modes} = _pty}},
|
{:pty, channel_id, want_reply?, {_term, width, height, _pixwidth, _pixheight, _opts}}},
|
||||||
state
|
state
|
||||||
) do
|
) do
|
||||||
|
Logger.debug("#{inspect(state.player_session)} has requested a PTY")
|
||||||
:ssh_connection.reply_request(connection_handler, want_reply?, :success, channel_id)
|
:ssh_connection.reply_request(connection_handler, want_reply?, :success, channel_id)
|
||||||
|
|
||||||
{:ok,
|
{:ok,
|
||||||
%{
|
%{
|
||||||
state
|
state
|
||||||
| pty: %{
|
| width: width,
|
||||||
term: term,
|
height: height
|
||||||
width: width,
|
|
||||||
height: height,
|
|
||||||
pixwidth: pixwidth,
|
|
||||||
pixheight: pixheight,
|
|
||||||
modes: modes
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -85,35 +125,37 @@ defmodule Chessh.SSH.Tui do
|
|||||||
|
|
||||||
def handle_ssh_msg(
|
def handle_ssh_msg(
|
||||||
{:ssh_cm, _connection_handler,
|
{:ssh_cm, _connection_handler,
|
||||||
{:window_change, _channel_id, width, height, pixwidth, pixheight}},
|
{:window_change, _channel_id, width, height, _pixwidth, _pixheight}},
|
||||||
state
|
state
|
||||||
) do
|
) do
|
||||||
Logger.debug("WINDOW CHANGE")
|
Logger.debug("WINDOW CHANGE")
|
||||||
# SSHnakes.Client.resize(state.client_pid, width, height)
|
# Chessh.SSH.Client.resize(state.client_pid, width, height)
|
||||||
|
|
||||||
{:ok,
|
{:ok,
|
||||||
%{
|
%{
|
||||||
state
|
state
|
||||||
| pty: %{
|
|
||||||
state.pty
|
|
||||||
| width: width,
|
| width: width,
|
||||||
height: height,
|
height: height
|
||||||
pixwidth: pixwidth,
|
|
||||||
pixheight: pixheight
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_ssh_msg(
|
def handle_ssh_msg(
|
||||||
{:ssh_cm, connection_handler, {:shell, channel_id, want_reply?}},
|
{:ssh_cm, connection_handler, {:shell, channel_id, want_reply?}},
|
||||||
state
|
%{width: width, height: height, player_session: player_session} = state
|
||||||
) do
|
) do
|
||||||
|
Logger.debug("Session #{player_session.id} requested shell")
|
||||||
:ssh_connection.reply_request(connection_handler, want_reply?, :success, channel_id)
|
:ssh_connection.reply_request(connection_handler, want_reply?, :success, channel_id)
|
||||||
|
|
||||||
{:ok, client_pid} =
|
{:ok, client_pid} =
|
||||||
GenServer.start_link(Chessh.SSH.Client, [self(), state.pty.width, state.pty.height])
|
GenServer.start_link(Client, [
|
||||||
|
%Client.State{
|
||||||
|
tui_pid: self(),
|
||||||
|
width: width,
|
||||||
|
player_session: player_session,
|
||||||
|
height: height
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
{:ok, %{state | client_pid: client_pid, shell: true}}
|
{:ok, %{state | client_pid: client_pid}}
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_ssh_msg(
|
def handle_ssh_msg(
|
||||||
@ -157,6 +199,14 @@ defmodule Chessh.SSH.Tui do
|
|||||||
{:stop, channel_id, state}
|
{:stop, channel_id, state}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def handle_ssh_msg(
|
||||||
|
msg,
|
||||||
|
%{channel_id: channel_id} = state
|
||||||
|
) do
|
||||||
|
Logger.debug("UNKOWN MESSAGE #{inspect(msg)}")
|
||||||
|
{:stop, channel_id, state}
|
||||||
|
end
|
||||||
|
|
||||||
def terminate(_reason, _state) do
|
def terminate(_reason, _state) do
|
||||||
:ok
|
:ok
|
||||||
end
|
end
|
||||||
|
5
mix.exs
5
mix.exs
@ -17,7 +17,7 @@ defmodule Chessh.MixProject do
|
|||||||
def application do
|
def application do
|
||||||
[
|
[
|
||||||
mod: {Chessh.Application, []},
|
mod: {Chessh.Application, []},
|
||||||
extra_applications: [:logger, :crypto, :ssh]
|
extra_applications: [:logger, :crypto, :syn, :ssh]
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -32,7 +32,8 @@ defmodule Chessh.MixProject do
|
|||||||
{:ecto_sql, "~> 3.9"},
|
{:ecto_sql, "~> 3.9"},
|
||||||
{:postgrex, "~> 0.16.5"},
|
{:postgrex, "~> 0.16.5"},
|
||||||
{:bcrypt_elixir, "~> 3.0"},
|
{:bcrypt_elixir, "~> 3.0"},
|
||||||
{:hammer, "~> 6.1"}
|
{:hammer, "~> 6.1"},
|
||||||
|
{:syn, "~> 3.3"}
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
1
mix.lock
1
mix.lock
@ -13,5 +13,6 @@
|
|||||||
"hammer": {:hex, :hammer, "6.1.0", "f263e3c3e9946bd410ea0336b2abe0cb6260af4afb3a221e1027540706e76c55", [:make, :mix], [{:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}], "hexpm", "b47e415a562a6d072392deabcd58090d8a41182cf9044cdd6b0d0faaaf68ba57"},
|
"hammer": {:hex, :hammer, "6.1.0", "f263e3c3e9946bd410ea0336b2abe0cb6260af4afb3a221e1027540706e76c55", [:make, :mix], [{:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}], "hexpm", "b47e415a562a6d072392deabcd58090d8a41182cf9044cdd6b0d0faaaf68ba57"},
|
||||||
"poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"},
|
"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"},
|
"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"},
|
||||||
|
"syn": {:hex, :syn, "3.3.0", "4684a909efdfea35ce75a9662fc523e4a8a4e8169a3df275e4de4fa63f99c486", [:rebar3], [], "hexpm", "e58ee447bc1094bdd21bf0acc102b1fbf99541a508cd48060bf783c245eaf7d6"},
|
||||||
"telemetry": {:hex, :telemetry, "1.1.0", "a589817034a27eab11144ad24d5c0f9fab1f58173274b1e9bae7074af9cbee51", [:rebar3], [], "hexpm", "b727b2a1f75614774cff2d7565b64d0dfa5bd52ba517f16543e6fc7efcc0df48"},
|
"telemetry": {:hex, :telemetry, "1.1.0", "a589817034a27eab11144ad24d5c0f9fab1f58173274b1e9bae7074af9cbee51", [:rebar3], [], "hexpm", "b727b2a1f75614774cff2d7565b64d0dfa5bd52ba517f16543e6fc7efcc0df48"},
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,8 @@ defmodule Chessh.SSH.AuthTest do
|
|||||||
password: String.to_charlist(@valid_user.password),
|
password: String.to_charlist(@valid_user.password),
|
||||||
auth_methods: auth_method,
|
auth_methods: auth_method,
|
||||||
silently_accept_hosts: true,
|
silently_accept_hosts: true,
|
||||||
user_dir: String.to_charlist(@client_test_keys_dir)
|
user_dir: String.to_charlist(@client_test_keys_dir),
|
||||||
|
disconnectfun: fn _reason -> send(parent, {:disconnected, self()}) end
|
||||||
)}
|
)}
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
@ -66,6 +67,20 @@ defmodule Chessh.SSH.AuthTest do
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "Player authentications are increased after a successful authentication" do
|
||||||
|
player_before = Repo.get_by(Player, username: @valid_user.username)
|
||||||
|
|
||||||
|
Chessh.SSH.Daemon.pwd_authenticate(
|
||||||
|
@valid_user.username,
|
||||||
|
@valid_user.password,
|
||||||
|
@localhost_inet
|
||||||
|
)
|
||||||
|
|
||||||
|
player_after = Repo.get_by(Player, username: @valid_user.username)
|
||||||
|
|
||||||
|
assert(player_after.authentications - player_before.authentications == 1)
|
||||||
|
end
|
||||||
|
|
||||||
test "INTEGRATION - Can ssh into daemon with password or public key" do
|
test "INTEGRATION - Can ssh into daemon with password or public key" do
|
||||||
{:ok, sup} = Task.Supervisor.start_link()
|
{:ok, sup} = Task.Supervisor.start_link()
|
||||||
test_pid = self()
|
test_pid = self()
|
||||||
@ -83,6 +98,8 @@ defmodule Chessh.SSH.AuthTest do
|
|||||||
send(test_pid, :connected_via_password)
|
send(test_pid, :connected_via_password)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
assert_receive(:connected_via_password, 2_000)
|
||||||
|
|
||||||
Task.Supervisor.start_child(sup, fn ->
|
Task.Supervisor.start_child(sup, fn ->
|
||||||
{:ok, conn} =
|
{:ok, conn} =
|
||||||
:ssh.connect(@localhost, Application.fetch_env!(:chessh, :port),
|
:ssh.connect(@localhost, Application.fetch_env!(:chessh, :port),
|
||||||
@ -96,13 +113,12 @@ defmodule Chessh.SSH.AuthTest do
|
|||||||
send(test_pid, :connected_via_public_key)
|
send(test_pid, :connected_via_public_key)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
assert_receive(:connected_via_password, 2_000)
|
|
||||||
assert_receive(:connected_via_public_key, 2_000)
|
assert_receive(:connected_via_public_key, 2_000)
|
||||||
|
|
||||||
cleanup()
|
cleanup()
|
||||||
end
|
end
|
||||||
|
|
||||||
test "INTEGRATION - Player cannot have more than specified concurrent sessions which are tracked by successful authentications and disconnections" do
|
test "INTEGRATION - SSH Sessions are closed once player has more than specified concurrent sessions which are tracked by successful authentications and disconnections" do
|
||||||
max_concurrent_user_sessions =
|
max_concurrent_user_sessions =
|
||||||
Application.get_env(:chessh, RateLimits)
|
Application.get_env(:chessh, RateLimits)
|
||||||
|> Keyword.get(:max_concurrent_user_sessions)
|
|> Keyword.get(:max_concurrent_user_sessions)
|
||||||
@ -130,10 +146,7 @@ defmodule Chessh.SSH.AuthTest do
|
|||||||
conn
|
conn
|
||||||
end)
|
end)
|
||||||
|
|
||||||
assert_receive(
|
assert_receive({:disconnected, _conn}, 2_000)
|
||||||
{:attempted, {:error, 'Unable to connect using the available authentication methods'}},
|
|
||||||
2000
|
|
||||||
)
|
|
||||||
|
|
||||||
# Give it time to send back the disconnection payload after session was opened
|
# Give it time to send back the disconnection payload after session was opened
|
||||||
# but over threshold
|
# but over threshold
|
||||||
|
Loading…
Reference in New Issue
Block a user