aboutsummaryrefslogtreecommitdiff
path: root/lib/ssh/conn_cli_manager.ex
diff options
context:
space:
mode:
authorElizabeth Hunt <elizabeth.hunt@simponic.xyz>2023-10-01 20:41:48 -0600
committerElizabeth Hunt <elizabeth.hunt@simponic.xyz>2023-10-01 20:41:48 -0600
commitffa3d553f693494c218a0244c946ba83dfbf7cd1 (patch)
tree092a824dad118c37960ab67da98cdbc445a35d2b /lib/ssh/conn_cli_manager.ex
downloadtronglessh-main.tar.gz
tronglessh-main.zip
Diffstat (limited to 'lib/ssh/conn_cli_manager.ex')
-rw-r--r--lib/ssh/conn_cli_manager.ex143
1 files changed, 143 insertions, 0 deletions
diff --git a/lib/ssh/conn_cli_manager.ex b/lib/ssh/conn_cli_manager.ex
new file mode 100644
index 0000000..19360f8
--- /dev/null
+++ b/lib/ssh/conn_cli_manager.ex
@@ -0,0 +1,143 @@
+defmodule TrongleSSH.SSH.ConnectionCLIManager do
+ alias TrongleSSH.SSH.{Session, Tui}
+ alias IO.ANSI
+ require Logger
+
+ @behaviour :ssh_server_channel
+ @session_closed_message [
+ ANSI.clear(),
+ ["This session has been closed."]
+ ]
+
+ defmodule State do
+ defstruct channel_id: nil,
+ width: nil,
+ height: nil,
+ client_pid: nil,
+ connection_ref: nil,
+ session: %Session{}
+ end
+
+ def init([%State{} = init_state]) do
+ {:ok, init_state}
+ end
+
+ def handle_msg({:ssh_channel_up, channel_id, connection_ref}, %State{} = state) do
+ connected_user =
+ :ssh.connection_info(connection_ref)
+ |> Keyword.fetch!(:user)
+ |> String.Chars.to_string()
+
+ {:ok,
+ %State{
+ state
+ | channel_id: channel_id,
+ connection_ref: connection_ref,
+ session: %Session{username: connected_user}
+ }}
+ end
+
+ def handle_msg(
+ {:EXIT, client_pid, _reason},
+ %State{client_pid: client_pid, channel_id: channel_id} = state
+ ) do
+ send(client_pid, :quit)
+ {:stop, channel_id, state}
+ end
+
+ def handle_msg(
+ {:send_data, data},
+ %State{connection_ref: connection_ref, channel_id: channel_id} = state
+ ) do
+ :ssh_connection.send(connection_ref, channel_id, data)
+ {:ok, state}
+ end
+
+ def handle_msg(
+ :session_closed,
+ %State{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
+ Logger.debug("Unknown msg #{inspect(msg)}, #{inspect(term)}")
+ end
+
+ def handle_ssh_msg(
+ {:ssh_cm, _connection_handler, {:data, _channel_id, _type, data}},
+ %State{} = state
+ ) do
+ send(state.client_pid, {:data, data})
+ {:ok, state}
+ end
+
+ def handle_ssh_msg(
+ {:ssh_cm, connection_handler,
+ {:pty, channel_id, want_reply?, {_term, width, height, _pixwidth, _pixheight, _opts}}},
+ %State{} = state
+ ) do
+ :ssh_connection.reply_request(connection_handler, want_reply?, :success, channel_id)
+
+ {:ok,
+ %{
+ state
+ | width: width,
+ height: height
+ }}
+ end
+
+ def handle_ssh_msg(
+ {:ssh_cm, connection_handler, {:env, channel_id, want_reply?, _var, _value}},
+ state
+ ) do
+ :ssh_connection.reply_request(connection_handler, want_reply?, :failure, channel_id)
+ {:ok, state}
+ end
+
+ def handle_ssh_msg(
+ {:ssh_cm, _connection_handler,
+ {:window_change, _channel_id, width, height, _pixwidth, _pixheight}},
+ %State{client_pid: client_pid} = state
+ ) do
+ send(client_pid, {:resize, {width, height}})
+
+ {:ok,
+ %State{
+ state
+ | width: width,
+ height: height
+ }}
+ end
+
+ def handle_ssh_msg(
+ {:ssh_cm, connection_handler, {:shell, channel_id, want_reply?}},
+ %State{width: width, height: height, session: session} = state
+ ) do
+ :ssh_connection.reply_request(connection_handler, want_reply?, :success, channel_id)
+
+ {:ok, client_pid} =
+ GenServer.start_link(Tui, [
+ %Tui.State{
+ connection_manager_pid: self(),
+ width: width,
+ height: height,
+ session: session
+ }
+ ])
+
+ send(client_pid, :refresh)
+ {:ok, %State{state | client_pid: client_pid}}
+ end
+
+ def handle_ssh_msg(
+ msg,
+ %State{channel_id: channel_id} = state
+ ) do
+ Logger.debug("unknown ssh #{inspect(msg)}")
+ {:stop, channel_id, state}
+ end
+
+ def terminate(_reason, _state), do: :ok
+end