using AspNetTools; using FxSsh; using FxSsh.Services; using MiniTerm; using System; using System.Configuration; using System.IO; using System.Net; using System.Net.Sockets; using System.Reflection; using System.Web; namespace WebTerminalServer { public class SshWsModule : IHttpModule { private SshServer _server; private IPEndPoint _listenEndPoint; private static void Log(string info) { File.AppendAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "App_Data", "logs.log"), info + Environment.NewLine); } public void Init(HttpApplication context) { Log("SshWsModule Init, OS:" + Environment.OSVersion.ToString()); AppDomain.CurrentDomain.UnhandledException += (sender, args) => { Log(args.ExceptionObject?.ToString()); }; //Create ssh server with available port _server = new SshServer(new StartingInfo(IPAddress.Loopback, 0, "SSH-2")); _server.AddHostKey("ssh-rsa", ConfigurationManager.AppSettings["SshHostKey"]); _server.ConnectionAccepted += (s2, e2) => { e2.ServiceRegistered += (s1, e1) => { if (e1 is UserauthService) { var service = (UserauthService)e1; service.Userauth += (s, e) => { e.Result = true; }; } else if (e1 is ConnectionService service) { int w = 0, h = 0; Terminal terminal = null; service.EnvReceived += (s, e) => Console.WriteLine("Received environment variable {0}:{1}", e.Name, e.Value); ; service.PtyReceived += (s, e) => { w = (int)e.WidthChars; h = (int)e.HeightRows; }; service.WindowChange += (sender, args) => { terminal?.ChangeWindowSize((short)args.WidthColumns, (short)args.HeightRows); }; service.CommandOpened += (s, e) => { Console.WriteLine($"Channel {e.Channel.ServerChannelId} runs {e.ShellType}: \"{e.CommandText}\"."); var allow = true; // func(e.ShellType, e.CommandText, e.AttachedUserauthArgs); if (!allow) return; if (e.ShellType == "shell") { // requirements: Windows 10 RedStone 5, 1809 // also, you can call powershell.exe Log("Pending Create Terminal"); try { terminal = new Terminal("cmd.exe", w, h); } catch (Exception exception) { Log(exception.ToString()); return; } Log("Terminal Created"); e.Channel.DataReceived += (ss, ee) => terminal.OnInput(ee); e.Channel.CloseReceived += (ss, ee) => terminal.OnClose(); terminal.DataReceived += (ss, ee) => e.Channel.SendData(ee); terminal.CloseReceived += (ss, ee) => e.Channel.SendClose(ee); terminal.Run(); } }; } }; }; _server.Start(); var field = _server.GetType().GetField("_listenser", BindingFlags.Instance | BindingFlags.NonPublic); var listener = (TcpListener)field.GetValue(_server); _listenEndPoint = (IPEndPoint)listener.Server.LocalEndPoint; context.PostMapRequestHandler += delegate { WebSocketForwardModule.ForwardCurrentContext("terminal", ConfigurationManager.AppSettings["PassCode"], _listenEndPoint); }; } public void Dispose() { _server?.Stop(); } } }