Skip to content

Instantly share code, notes, and snippets.

@antoniomika
Created November 2, 2017 04:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save antoniomika/2f56cd2d62145d10e10423fbfaf7b553 to your computer and use it in GitHub Desktop.
Save antoniomika/2f56cd2d62145d10e10423fbfaf7b553 to your computer and use it in GitHub Desktop.
SeeShell
<html>
<head>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/xterm/2.9.2/xterm.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/xterm/2.9.2/addons/fullscreen/fullscreen.min.css" />
<link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/themes/smoothness/jquery-ui.css" />
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/jquery-ui.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/xterm/2.9.2/xterm.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/xterm/2.9.2/addons/fullscreen/fullscreen.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/xterm/2.9.2/addons/fit/fit.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/xterm/2.9.2/addons/attach/attach.min.js"></script>
<style>
body {
font-family: "DejaVu Sans Mono", "Liberation Mono", monospace;
font-size: 11px;
}
</style>
<script type="text/javascript">
$(function() {
var ip = window.location.hash.substr(1) || prompt("Address:");
var websocket = new WebSocket("ws://" + window.location.hostname + ":" + window.location.port + "/ws/" + ip);
websocket.onopen = function(evt) {
term = new Terminal({
cursorBlink: true,
cols: 250,
rows: 50
});
term.open(document.getElementById("terminal-container"), true);
term.toggleFullscreen(true);
term.attach(websocket);
}
});
</script>
</head>
<div id="terminal-container"></div>
</html>
package main
import (
"flag"
"log"
"net/http"
"text/template"
"github.com/fatih/color"
"github.com/gorilla/mux"
"github.com/gorilla/websocket"
"net"
"time"
"sync"
"bufio"
)
var httpAddr = flag.String("http-addr", "localhost:8080", "HTTP/WS service address")
var tcpAddr = flag.String("tcp-add", "localhost:8081", "TCP service address")
var indexTemplate = template.Must(template.ParseFiles("templates/index.html"))
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool { return true },
}
var webSocketClients = make(map[string][]*websocket.Conn)
var tcpClients = make(map[string]net.Conn)
var mutex = &sync.Mutex{}
func logHTTP(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
color.Set(color.FgYellow)
log.Printf("%s %s %s", r.RemoteAddr, r.Method, r.URL)
color.Unset()
handler.ServeHTTP(w, r)
})
}
func main() {
flag.Parse()
log.SetFlags(0)
r := mux.NewRouter()
r.HandleFunc("/", indexHandler)
r.HandleFunc("/ws/{id}", wsHandler)
http.Handle("/", r)
color.Set(color.FgGreen)
log.Println("Running HTTP and WS server on:", *httpAddr)
color.Unset()
color.Set(color.FgRed)
go http.ListenAndServe(*httpAddr, logHTTP(http.DefaultServeMux))
color.Unset()
color.Set(color.FgGreen)
log.Println("Running TCP server on:", *tcpAddr)
color.Unset()
startTCP()
}
func indexHandler(w http.ResponseWriter, r *http.Request) {
indexTemplate.Execute(w, r.Host)
}
func wsHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
pathKey := vars["id"]
c, err := upgrader.Upgrade(w, r, nil)
color.Set(color.FgBlue)
log.Println("New WebSocket Connection From:", r.RemoteAddr)
log.Println("Path:", pathKey)
color.Unset()
if err != nil {
color.Set(color.FgRed)
log.Println("Upgrade error:", err)
color.Unset()
return
}
mutex.Lock()
if _, ok := webSocketClients[pathKey]; ok {
webSocketClients[pathKey] = append(webSocketClients[pathKey], c)
} else {
webSocketClients[pathKey] = []*websocket.Conn{c}
}
mutex.Unlock()
for {
_, _, err := c.ReadMessage()
if err != nil {
color.Set(color.FgRed)
log.Println("wsReader error:", err)
color.Unset()
break
}
// This will redirect input from the web based terminal to the client (netcat).
// If netcat bidirectionally opened stdin and stdout, you could control your process with that.
/*if val, ok := tcpClients[pathKey]; ok {
writer := bufio.NewWriter(val)
writer.Write(data)
writer.Flush()
}*/
}
defer func() {
c.Close()
color.Set(color.FgMagenta)
log.Println("Closed WebSocket Connection From:", r.RemoteAddr)
color.Unset()
mutex.Lock()
if _, ok := webSocketClients[pathKey]; ok {
newclients := []*websocket.Conn{}
for _, varclient := range webSocketClients[pathKey] {
if c != varclient {
newclients = append(newclients, varclient)
}
}
webSocketClients[pathKey] = newclients
} else {
webSocketClients[pathKey] = []*websocket.Conn{}
}
mutex.Unlock()
}()
}
func startTCP() {
socket, err := net.Listen("tcp", *tcpAddr)
if err != nil {
log.Fatal(err)
}
defer socket.Close()
for {
conn, err := socket.Accept()
if err != nil {
log.Println(err)
continue
}
color.Set(color.FgBlue)
log.Println("New TCPServer Connection From:", conn.RemoteAddr().String())
color.Unset()
go handleTCP(conn)
}
}
func handleTCP(conn net.Conn) {
tcpClients[conn.RemoteAddr().String()] = conn
conn.SetReadDeadline(time.Now())
reader := bufio.NewReader(conn)
writer := bufio.NewWriter(conn)
writer.Write([]byte("Access the RTV at http://" + *httpAddr + "/#" + conn.RemoteAddr().String() + "\n"))
writer.Flush()
for {
zero := make([]byte, 0)
if _, err := conn.Read(zero); err != nil {
log.Println("Foobbar", err)
break
} else {
conn.SetReadDeadline(time.Now().Add(30 * time.Millisecond))
}
mutex.Lock()
if data, _ := reader.Peek(1); len(data) > 0 {
if val, ok := webSocketClients[conn.RemoteAddr().String()]; ok {
data, _, err := reader.ReadLine()
if err != nil {
color.Set(color.FgRed)
log.Println("TCPReader error:", err)
color.Unset()
}
for _, wsClient := range val {
wsWriter, err := wsClient.NextWriter(websocket.TextMessage)
if err != nil {
color.Set(color.FgRed)
log.Println("wsWriter error:", err)
color.Unset()
} else {
wsWriter.Write(data)
wsWriter.Close()
}
}
}
}
mutex.Unlock()
}
defer func() {
conn.Close()
color.Set(color.FgMagenta)
log.Println("Closed TCPServer Connection From:", conn.RemoteAddr().String())
color.Unset()
}()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment