summaryrefslogtreecommitdiff
path: root/lib/chessh/ssh
diff options
context:
space:
mode:
authorLogan Hunt <loganhunt@simponic.xyz>2022-12-30 05:53:15 -0700
committerGitHub <noreply@github.com>2022-12-30 05:53:15 -0700
commit52fbc0b0161d2d30583d7f04eef57a29e441e1d2 (patch)
treef882037a2820973ba6dc5f64206b01dba03266d8 /lib/chessh/ssh
parentc143bb549c53f2737c41cdfce6cc2598c5489bdc (diff)
parente7d8c61487815bd90ec5834dad5e6f64dd951b53 (diff)
downloadchessh-52fbc0b0161d2d30583d7f04eef57a29e441e1d2.tar.gz
chessh-52fbc0b0161d2d30583d7f04eef57a29e441e1d2.zip
Merge pull request #2 from Simponic/erlang_ssh_server
Erlang ssh server #2
Diffstat (limited to 'lib/chessh/ssh')
-rw-r--r--lib/chessh/ssh/cli.ex26
-rw-r--r--lib/chessh/ssh/daemon.ex75
-rw-r--r--lib/chessh/ssh/server_key.ex7
3 files changed, 87 insertions, 21 deletions
diff --git a/lib/chessh/ssh/cli.ex b/lib/chessh/ssh/cli.ex
new file mode 100644
index 0000000..71d789b
--- /dev/null
+++ b/lib/chessh/ssh/cli.ex
@@ -0,0 +1,26 @@
+defmodule Chessh.SSH.Cli do
+ @behaviour :ssh_server_channel
+
+ def init(_args) do
+ {:ok, %{}}
+ end
+
+ def handle_msg(_message, state) do
+ {:ok, state}
+ end
+
+ def handle_ssh_msg(
+ {:ssh_cm, _connection_handler, {:exit_signal, channel_id, _signal, _err, _lang}},
+ state
+ ) do
+ {:stop, channel_id, state}
+ end
+
+ def handle_ssh_msg(_message, state) do
+ {:ok, state}
+ end
+
+ def terminate(_reason, _state) do
+ :ok
+ end
+end
diff --git a/lib/chessh/ssh/daemon.ex b/lib/chessh/ssh/daemon.ex
index 9f17f75..b341833 100644
--- a/lib/chessh/ssh/daemon.ex
+++ b/lib/chessh/ssh/daemon.ex
@@ -1,6 +1,10 @@
defmodule Chessh.SSH.Daemon do
+ alias Chessh.{Repo, PlayerSession, Utils}
alias Chessh.Auth.PasswordAuthenticator
use GenServer
+ import Ecto.Query
+
+ require Logger
def start_link(_) do
GenServer.start_link(__MODULE__, %{
@@ -13,33 +17,33 @@ defmodule Chessh.SSH.Daemon do
{:ok, state}
end
- def pwd_authenticate(username, password) do
- # TODO - check concurrent sessions
- PasswordAuthenticator.authenticate(
- String.Chars.to_string(username),
- String.Chars.to_string(password)
- )
- end
-
- def pwd_authenticate(username, password, inet) do
+ def pwd_authenticate(username, password, {ip, _port}) do
[jail_timeout_ms, jail_attempt_threshold] =
Application.get_env(:chessh, RateLimits)
|> Keyword.take([:jail_timeout_ms, :jail_attempt_threshold])
|> Keyword.values()
- {ip, _port} = inet
rateId = "failed_password_attempts:#{Enum.join(Tuple.to_list(ip), ".")}"
- if pwd_authenticate(username, password) do
- true
- else
- case Hammer.check_rate_inc(rateId, jail_timeout_ms, jail_attempt_threshold, 1) do
- {:allow, _count} ->
- false
+ case PasswordAuthenticator.authenticate(
+ String.Chars.to_string(username),
+ String.Chars.to_string(password)
+ ) do
+ false ->
+ case Hammer.check_rate_inc(rateId, jail_timeout_ms, jail_attempt_threshold, 1) do
+ {:allow, _count} ->
+ false
+
+ {:deny, _limit} ->
+ :disconnect
+ end
- {:deny, _limit} ->
- :disconnect
- end
+ x ->
+ if PlayerSession.player_within_concurrent_sessions_and_satisfies(username, fn _player ->
+ x
+ end),
+ do: true,
+ else: :disconnect
end
end
@@ -53,10 +57,13 @@ defmodule Chessh.SSH.Daemon do
case :ssh.daemon(
port,
+ # shell: fn _username, _peer -> Process.sleep(5000) end,
system_dir: key_dir,
pwdfun: &pwd_authenticate/4,
key_cb: Chessh.SSH.ServerKey,
- # disconnectfun:
+ ssh_cli: {Chessh.SSH.Cli, []},
+ # connectfun: &on_connect/3,
+ disconnectfun: &on_disconnect/1,
id_string: :random,
subsystems: [],
parallel_login: true,
@@ -74,4 +81,32 @@ defmodule Chessh.SSH.Daemon do
end
def handle_info(_, state), do: {:noreply, state}
+
+ # defp on_connect(username, _inet, _method) do
+ # Logger.debug("#{inspect(self())} connected and is authenticated as #{username}")
+ #
+ # case Repo.get_by(Player, username: String.Chars.to_string(username)) do
+ # nil ->
+ # nil
+ #
+ # player ->
+ # Repo.insert(%PlayerSession{
+ # login: DateTime.utc_now(),
+ # node_id: System.fetch_env!("NODE_ID"),
+ # player: player,
+ # process: pid_to_str(self())
+ # })
+ # end
+ # end
+
+ defp on_disconnect(_reason) do
+ Logger.debug("#{inspect(self())} disconnected")
+
+ Repo.delete_all(
+ from(p in PlayerSession,
+ where: p.node_id == ^System.fetch_env!("NODE_ID"),
+ where: p.process == ^Utils.pid_to_str(self())
+ )
+ )
+ end
end
diff --git a/lib/chessh/ssh/server_key.ex b/lib/chessh/ssh/server_key.ex
index 72a4fbb..5252624 100644
--- a/lib/chessh/ssh/server_key.ex
+++ b/lib/chessh/ssh/server_key.ex
@@ -1,9 +1,14 @@
defmodule Chessh.SSH.ServerKey do
+ alias Chessh.PlayerSession
alias Chessh.Auth.KeyAuthenticator
+
@behaviour :ssh_server_key_api
def is_auth_key(key, username, _daemon_options) do
- KeyAuthenticator.authenticate(username, key)
+ PlayerSession.player_within_concurrent_sessions_and_satisfies(
+ username,
+ &KeyAuthenticator.authenticate(&1, key)
+ )
end
def host_key(algorithm, daemon_options) do