diff --git a/app/app.go b/app/app.go index 31481e1..81b3a30 100644 --- a/app/app.go +++ b/app/app.go @@ -29,8 +29,9 @@ type App struct { command []string options *Options - upgrader *websocket.Upgrader - server *manners.GracefulServer + upgrader *websocket.Upgrader + server *manners.GracefulServer + authToken string titleTemplate *template.Template } @@ -88,19 +89,13 @@ func New(command []string, options *Options) (*App, error) { WriteBufferSize: 1024, Subprotocols: []string{"gotty"}, }, + authToken: generateRandomString(20), titleTemplate: titleTemplate, }, nil } -func ApplyConfigFile(options *Options, configFilePath string) error { - if err := applyConfigFile(options, configFilePath); err != nil { - return err - } - return nil -} - -func applyConfigFile(options *Options, filePath string) error { +func ApplyConfigFile(options *Options, filePath string) error { filePath = ExpandHomeDir(filePath) if _, err := os.Stat(filePath); os.IsNotExist(err) { return err @@ -146,19 +141,15 @@ func applyConfigFile(options *Options, filePath string) error { return nil } -func ExpandHomeDir(path string) string { - if path[0:2] == "~/" { - return os.Getenv("HOME") + path[1:] - } else { - return path - } -} - func (app *App) Run() error { if app.options.PermitWrite { log.Printf("Permitting clients to write input to the PTY.") } + if app.options.Once { + log.Printf("Once option is provided, accepting only one client") + } + path := "" if app.options.EnableRandomUrl { path += "/" + generateRandomString(app.options.RandomUrlLength) @@ -167,31 +158,23 @@ func (app *App) Run() error { endpoint := net.JoinHostPort(app.options.Address, app.options.Port) wsHandler := http.HandlerFunc(app.handleWS) + customIndexHandler := http.HandlerFunc(app.handleCustomIndex) + authTokenHandler := http.HandlerFunc(app.handleAuthToken) staticHandler := http.FileServer( &assetfs.AssetFS{Asset: Asset, AssetDir: AssetDir, Prefix: "static"}, ) - if app.options.Once { - log.Printf("Once option is provided, accepting only one client") - } - var siteMux = http.NewServeMux() if app.options.IndexFile != "" { log.Printf("Using index file at " + app.options.IndexFile) - indexHandler := http.HandlerFunc( - func(w http.ResponseWriter, r *http.Request) { - http.ServeFile(w, r, ExpandHomeDir(app.options.IndexFile)) - }, - ) - siteMux.Handle(path+"/", indexHandler) + siteMux.Handle(path+"/", customIndexHandler) } else { siteMux.Handle(path+"/", http.StripPrefix(path+"/", staticHandler)) } - + siteMux.Handle(path+"/auth_token.js", authTokenHandler) siteMux.Handle(path+"/js/", http.StripPrefix(path+"/", staticHandler)) siteMux.Handle(path+"/favicon.png", http.StripPrefix(path+"/", staticHandler)) - siteMux.Handle(path+"/ws", wsHandler) siteHandler := http.Handler(siteMux) @@ -200,6 +183,11 @@ func (app *App) Run() error { siteHandler = wrapBasicAuth(siteHandler, app.options.Credential) } + wsMux := http.NewServeMux() + wsMux.Handle("/", siteHandler) + wsMux.Handle(path+"/ws", wsHandler) + siteHandler = (http.Handler(wsMux)) + siteHandler = wrapLogger(siteHandler) scheme := "http" @@ -264,6 +252,12 @@ func (app *App) handleWS(w http.ResponseWriter, r *http.Request) { return } + _, initMessage, err := conn.ReadMessage() + if err != nil || string(initMessage) != app.authToken { + log.Print("Failed to authenticate websocket connection") + return + } + cmd := exec.Command(app.command[0], app.command[1:]...) ptyIo, err := pty.Start(cmd) if err != nil { @@ -283,6 +277,14 @@ func (app *App) handleWS(w http.ResponseWriter, r *http.Request) { context.goHandleClient() } +func (app *App) handleCustomIndex(w http.ResponseWriter, r *http.Request) { + http.ServeFile(w, r, ExpandHomeDir(app.options.IndexFile)) +} + +func (app *App) handleAuthToken(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("var gotty_auth_token = '" + app.authToken + "';")) +} + func (app *App) Exit() (firstCall bool) { if app.server != nil { log.Printf("Received Exit command, waiting for all clients to close sessions...") @@ -355,3 +357,11 @@ func listAddresses() (addresses []string) { return } + +func ExpandHomeDir(path string) string { + if path[0:2] == "~/" { + return os.Getenv("HOME") + path[1:] + } else { + return path + } +} diff --git a/app/resource.go b/app/resource.go index 416047a..c8e7acd 100644 --- a/app/resource.go +++ b/app/resource.go @@ -91,7 +91,7 @@ func staticFaviconPng() (*asset, error) { return a, nil } -var _staticIndexHtml = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x74\x90\xc1\x52\xc4\x20\x0c\x86\xef\x3e\x45\xc4\xf1\xe6\x94\x7a\xdd\xd2\x5e\x7d\x81\xbd\x78\x64\x4b\xb6\x64\xa5\xc0\x40\x5c\xed\x38\xbe\xbb\xb0\xd8\x93\xe3\x89\x3f\xf9\xff\x49\x3e\xa2\xee\x4d\x98\x79\x8b\x08\x96\x57\x37\xdd\xa9\xf6\x00\x28\x8b\xda\x54\x51\x24\x13\x3b\x9c\x5e\xc2\xf1\xf8\xaa\x64\x2b\x9a\x91\x79\x2b\xfa\x14\xcc\xf6\x04\x0f\x8c\x69\x25\xaf\x1d\x7c\xc5\x90\x89\x29\xf8\x03\xe8\x53\x0e\xee\x9d\x71\x00\x8b\xb4\x58\x3e\xc0\x73\xdf\x3f\x0e\xf0\x41\x86\xed\x5e\xac\x3a\x2d\x54\xc2\x7d\xfc\x1c\xbe\x95\x6c\x43\xdb\x02\x47\xfe\x0d\x12\xba\x51\xd0\x1c\xbc\x80\x4a\x5a\xf4\xaa\x17\x94\xd1\x2f\x02\x6c\xc2\xf3\x28\xce\xfa\x5a\xfd\xae\xb6\x6e\xf0\x72\xa7\x57\x15\xee\x77\x98\xa1\x2b\x90\x19\xc5\x0e\x2a\x26\x25\x4b\x6f\xff\xcb\x9c\x28\x32\xe4\x34\x8f\xa2\x93\x97\x2c\x6d\xcd\x75\x97\x5c\x63\xcd\xfc\x2f\xb9\x04\xe6\xed\x4f\x52\xc9\xb6\xbb\xc0\xdc\x6e\xfa\x13\x00\x00\xff\xff\x96\x39\xb4\x53\x6b\x01\x00\x00") +var _staticIndexHtml = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x84\x90\xc1\x52\xc3\x20\x10\x86\xef\x3e\xc5\x8a\xe3\xcd\x09\xf1\xda\x90\x5c\x7d\x81\x5e\x3c\x39\x34\x6c\xc3\xb6\x04\x32\xb0\xad\x66\x1c\xdf\x5d\x28\xe6\xa4\x33\x9e\xf8\x77\xf7\x9b\xe5\x03\x75\x6f\xc2\xc8\xeb\x82\x60\x79\x76\xc3\x9d\xaa\x07\x80\xb2\xa8\x4d\x09\x39\x32\xb1\xc3\xe1\x25\xec\xf7\xaf\x4a\xd6\xa2\x0e\x12\xaf\x39\x1f\x82\x59\x9f\xe0\x81\x31\xce\xe4\xb5\x83\xcf\x25\x24\x62\x0a\x7e\x07\xfa\x90\x82\xbb\x30\x76\x60\x91\x26\xcb\x3b\x78\x6e\xdb\xc7\x0e\xde\xc9\xb0\xdd\x8a\x59\xc7\x89\x32\xdc\x2e\x1f\xdd\x97\x92\x75\x69\xbd\xc0\x91\x3f\x43\x44\xd7\x0b\x1a\x83\x17\x50\x4c\x73\x9e\xf5\x84\x72\xf1\x93\x00\x1b\xf1\xd8\x8b\xa3\xbe\x96\x79\x53\x5a\x37\x79\xb9\xd9\xab\x22\xf7\xb3\xcc\xd0\x15\xc8\xf4\x62\x13\x15\x83\x92\xb9\xb7\xbd\x65\x8c\xb4\x30\xa4\x38\xf6\xa2\x91\xa7\x24\x6d\xe1\x9a\x53\x2a\x58\x1d\xfe\x49\xea\x0b\xdb\x37\x0e\x67\xf4\xff\xb3\x79\xeb\x14\x98\xd7\x5f\xa4\x92\xd5\x33\x8b\xdf\xfe\xff\x3b\x00\x00\xff\xff\x35\xaf\x3e\x6a\x97\x01\x00\x00") func staticIndexHtmlBytes() ([]byte, error) { return bindataRead( @@ -106,12 +106,12 @@ func staticIndexHtml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "static/index.html", size: 363, mode: os.FileMode(436), modTime: time.Unix(1440919621, 0)} + info := bindataFileInfo{name: "static/index.html", size: 407, mode: os.FileMode(436), modTime: time.Unix(1441003850, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _staticJsGottyJs = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x94\x56\x5f\x6f\xe2\x38\x10\x7f\xef\xa7\xb0\xf2\x82\x73\x47\x5d\xb8\x93\xee\x01\xc4\x9d\x74\x55\x57\xda\x3f\xda\xae\x0a\xbb\x7d\xa8\xfa\x60\x92\x01\xb2\x18\x1b\xd9\x4e\x23\x76\xc5\x77\xdf\x99\x10\x20\x04\xa7\x6c\xfd\x10\x19\xcf\xcc\x6f\xfe\x78\x7e\x63\xf8\x2c\xd7\x89\xcf\x8c\xe6\x31\xfb\x79\xc5\x70\xbd\x48\xcb\x16\xde\xaf\xdd\x9d\x96\x53\x05\x29\x1b\xb1\x22\xd3\xa9\x29\x84\x32\x89\x24\x55\xb1\xb6\xc6\x9b\xc4\x28\x36\x1a\xb1\xa8\xd4\x1d\x44\xc3\x83\x71\x6e\x51\xc0\xf8\x09\xc6\x7f\xac\x53\x38\x37\xb8\xb9\xe9\xb0\x01\x6d\x69\x17\xb3\x3f\xcf\x90\x17\xc6\xf9\xc0\xf1\x5a\xfa\x85\x96\x2b\x40\x11\x1a\x77\x8e\xbe\xf6\x91\x38\xf4\xf8\x14\xcd\x8d\xf7\x9b\xe8\xf9\x28\x96\xb9\x37\x0f\x90\x18\xad\x21\xf1\xa8\x72\xdd\x1f\x5e\x1d\x84\x66\x0d\xfa\x91\x0c\xcf\x4a\xb0\xd7\x28\x48\xaa\xa1\x60\x8f\x30\x1d\x9b\x64\x09\x9e\x63\x72\xdd\xa3\xd7\xb8\x82\xdb\x1b\x78\xb0\xab\xda\x51\xe1\x84\xd1\xe4\xa6\xee\x04\x5e\x40\xfb\xba\x27\x5a\x0b\xb2\x14\x29\xcc\x64\xae\xfc\xd8\x1b\x2b\xe7\x50\xf9\x56\xd9\x54\x54\x27\xe2\x13\x16\x44\xf1\x78\x78\xd1\x56\x24\x0a\xa4\xe5\xf5\xf8\x68\x91\x66\x05\xbb\xb3\x9a\xe0\x27\xd3\x3b\xcc\x33\x4d\x31\x07\xff\xc5\xc2\xcc\xf1\x58\x38\xcc\x3d\x72\xa0\xd3\x6b\xd0\x89\x49\x33\x3d\x8f\xba\x2c\xb2\xb2\x88\x82\x96\x46\xef\x91\x1f\x40\xa6\x9b\xb6\x22\xd7\x6b\x97\x19\xd4\x2a\x8d\x33\x23\xd6\xb9\x5b\x9c\xc5\x44\x0b\x65\x46\x7f\x9b\x7c\x84\x8d\xf3\xd6\x2c\xa1\x8e\x8c\x27\x21\xf0\xea\x26\x28\x78\x1e\xf5\x22\xec\x21\x52\x1c\x9e\xe9\x6d\xc3\xee\xc8\x6e\xec\x2d\x66\x8c\xbe\x9a\xee\xdb\x22\x3c\x66\xef\xb2\x1f\x27\x41\x62\xdb\xe4\x2b\xed\xba\xcc\x9a\xc2\x5d\x0a\x37\x28\xa4\x15\xf5\x29\x8f\x0f\xe3\xfb\xcf\xc2\x95\xb1\x65\xb3\x4d\xbb\x36\xad\xb0\xa3\xfa\xaa\x22\x1b\xec\x37\xdd\x8b\x16\x94\xc2\xa0\xfc\xbe\xae\xbb\x6d\x95\xc6\x41\xc9\xf9\x69\xe8\x6e\x76\xbd\xa2\x9d\x97\x4a\xe1\x85\x4c\x8d\xb4\x69\x93\x1b\x4d\xbb\x8a\x2a\x09\x92\xc4\x03\x4f\x4d\x92\xaf\x90\x8d\xd4\xe8\x77\x0a\x68\xfb\xff\xe6\x3d\x76\x89\xaf\xae\x2f\x8a\x6b\x78\xdb\x26\xb3\x57\xe0\xdc\x8e\xa7\xaf\x93\x3b\x95\x5e\xa2\x52\x29\x13\xf4\x43\x38\x95\x25\xc0\xfb\x8d\x60\x5d\x91\xf9\x64\xc1\x8f\x7a\x4f\xbd\xe7\x26\x56\x22\x1d\xb0\x4e\xaf\x33\x68\x29\x87\x11\x85\xcd\x3c\x7c\x9d\xbc\xeb\xff\xc3\x09\x23\xd0\xe8\x53\x0b\x72\x39\x0c\xc0\xf6\xdb\x60\x91\xfd\x8f\xe5\x48\x9e\x64\x5e\xc1\x9b\x71\xff\x0a\xe0\xae\x71\xb0\x80\xc5\x61\x02\x34\x64\xcb\x4e\x5e\x4b\xeb\x5a\xc1\xef\xa7\xdf\x71\x86\x8b\x25\x32\x8f\xd7\x6c\x63\x31\x33\xf6\x4e\x62\xd9\x0e\x77\x80\x2a\x6d\xbc\xc2\x97\xc0\x19\x05\xf8\xb0\xcc\x79\x34\x06\xef\x89\xd5\xc4\x24\xb4\xc1\x6f\x34\x28\x7f\xd4\x63\x7b\x42\xc9\x73\x20\x9c\x43\x69\x1a\x33\x12\xd5\xbb\xbf\x63\xbf\x7d\x4b\xfd\xfe\x0e\xd4\xaf\xf9\xb4\x5d\xae\x60\x00\xfe\x48\xcc\x6d\xa3\xb7\x13\x65\xdc\xe5\xce\xce\x66\x8c\x53\x15\x42\xf5\x2e\xab\x93\xeb\x0b\x04\x3d\x68\xd2\xa4\x5d\x98\xe2\xfe\x05\xac\x92\x1b\x1e\xdd\xee\x32\x43\xd7\xec\x96\x62\x49\xf1\xbd\xd1\xb9\x52\x4d\x82\x9f\xd2\xdb\x6e\x0e\x35\xa9\x7b\x6a\x66\x07\xd6\x1a\x7b\x92\x1d\x1d\x34\xb3\x68\x47\xab\x61\xee\xfe\x45\x1c\xde\xaa\xf2\x5f\x40\xcd\xae\xed\xe5\xa3\xca\x9d\x5e\xe1\xbf\x23\xd6\x6b\x46\x80\x1d\x35\xc9\x56\x60\x72\xcf\x77\x7e\xba\x8d\x7b\xff\x83\xf5\x7b\xbd\x5e\x20\xb6\x6d\xcc\xe3\xab\x5f\x01\x00\x00\xff\xff\x42\x24\x4b\x87\xdd\x09\x00\x00") +var _staticJsGottyJs = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x94\x56\xdd\x8e\xda\x3a\x10\xbe\xdf\xa7\xb0\x72\x83\x73\x0e\x9b\x85\x73\xa4\x5e\x80\x68\xa5\xae\xb6\x52\x7f\xd4\xad\x16\xda\xbd\x58\xad\x56\x26\x19\x48\x8a\xb1\x91\x3d\xd9\x88\x56\xbc\x7b\xc7\x21\x40\x08\xce\xd2\xf5\x45\x64\x3c\xdf\x7c\xf3\xe3\x99\x31\x7c\x96\xab\x18\x33\xad\x78\xc8\x7e\x5f\x30\x5a\xcf\xc2\xb0\x14\x71\x65\x6f\x94\x98\x4a\x48\xd8\x88\x15\x99\x4a\x74\x11\x49\x1d\x0b\x07\x8d\x56\x46\xa3\x8e\xb5\x64\xa3\x11\x0b\x4a\xec\x20\x18\xee\x95\x73\x43\x02\xc6\x8f\x38\xde\xb1\x4e\x61\xed\xe0\xea\xaa\xc3\x06\x6e\xeb\x76\x21\xfb\xf7\x84\x39\xd5\x16\x3d\xc7\x2b\x81\xa9\x12\x4b\x20\x11\x29\x77\x0e\xb6\x76\x9e\x58\xb2\xf8\x10\xcc\x35\xe2\x3a\x78\x3c\x88\x45\x8e\xfa\x0e\x62\xad\x14\xc4\x48\x90\xcb\xfe\xf0\x62\x2f\xd4\x2b\x50\xf7\x4e\xf1\x24\x05\x3b\x44\xe1\xa4\x0a\x0a\x76\x0f\xd3\xb1\x8e\x17\x80\x9c\x82\xeb\x1e\xac\x86\x15\xdd\x4e\x01\xc1\x2c\x6b\x47\x85\x8d\xb4\x72\x66\xea\x46\xe0\x19\x14\xd6\x2d\x55\x48\x0b\x2a\xe1\x65\x04\x4f\xe4\x76\xfa\x84\x7a\x01\xaa\x6e\xc0\xad\xd4\x59\x88\x12\x98\x89\x5c\xe2\x18\xb5\x11\x73\xa8\x7c\x94\xd9\x34\xaa\x4e\xa2\x2f\x94\x38\xc9\xc3\xe1\x59\xdd\x28\x96\x20\x0c\x6f\x9a\x71\xc8\x8a\x76\xab\x35\xa1\x4f\xa6\xb6\x9c\x27\xc8\x68\x0e\xf8\xcd\xc0\xcc\xf2\x90\xa2\x40\x1e\xb8\x50\x2e\x41\xc5\x3a\xc9\xd4\x3c\xe8\xb2\xc0\x88\x22\xf0\x6a\x6a\xb5\x63\xbe\x03\x91\xac\xdb\x2e\xa3\x9e\xe3\x4c\x13\xaa\x54\xce\x74\xb4\xca\x6d\x7a\xe2\x93\x5b\x24\xd3\xea\xc7\xe4\x33\xac\x2d\x1a\xca\x64\x9d\x99\x4e\x7c\xe4\xf5\x7b\x08\x7a\x01\xd5\x9a\x03\x0e\x4f\x70\x1b\xbf\x39\xa7\x37\x46\x43\x11\x93\xad\xa6\xf9\x36\x0f\x0f\xd1\xdb\xec\xd7\x91\x93\x54\x5e\xf9\x52\xd9\x2e\x33\xba\xb0\xe7\xdc\xf5\x0a\xdd\x0a\xfa\x2e\x8e\x4f\xe3\xdb\xaf\x91\x2d\x7d\xcb\x66\xeb\x76\xb4\x5b\x7e\x43\xf5\x55\x79\x36\xd8\x6d\xba\x67\x35\x5c\x08\x83\xf2\xfb\x32\x76\xd3\x2a\x0d\xbd\x92\xd3\x53\xdf\xdd\x6c\x6b\x45\x59\x14\x52\xd2\x85\x4c\xb5\x30\x49\xb3\x37\x9a\x7a\x55\xab\xc4\xd4\x24\x08\x3c\xd1\x71\xbe\xa4\xae\x75\x85\x7e\x23\xc1\x6d\xdf\xaf\x3f\x52\x95\x60\x75\x7d\x41\x58\xe3\xdb\x34\x27\xc0\x12\xac\xdd\xf6\xe9\xcb\x43\x20\x11\x28\x08\x54\xca\x22\xf7\x23\xb2\x32\x8b\x81\xf7\x1b\xce\xda\x22\xc3\x38\xe5\x07\xdc\x43\xef\xb1\xc9\x15\x0b\x0b\xac\xd3\xeb\x0c\x5a\xd2\xa1\xa3\xc2\x64\x08\xdf\x27\x1f\xfa\x6f\xb8\xe3\xf0\x14\xfa\xd4\x80\x58\x0c\x3d\xb4\xfd\x36\x5a\xea\xfe\xfb\x72\x74\x4f\x32\x94\xf0\x6a\xde\xff\x3c\xbc\x2b\x1a\x2c\x60\x68\x98\x80\x1b\xc6\x65\x25\xaf\x84\xb1\xad\xe4\xb7\xd3\x9f\x34\xeb\xa3\x05\x75\x1e\xaf\xe9\x86\xd1\x4c\x9b\x1b\x41\x69\xdb\xdf\x01\x41\xda\xfa\x8a\x5e\x0c\xab\x25\xd0\x03\x34\xe7\xc1\x18\x10\x5d\x57\xbb\x4e\x22\x1d\xfa\x06\x83\xf2\x47\xdd\xb7\x07\x92\x3c\x7a\xdc\xd9\xa7\xa6\x31\x23\x09\xde\xfd\x1b\xfd\xcd\x6b\xf2\xf7\xbf\x27\x7f\xcd\x27\xf0\x7c\x06\x3d\xf4\x87\xc6\xdc\x34\x6a\x3b\x96\xda\x9e\xaf\xec\x6c\xc6\xb8\xcb\x82\x2f\xdf\x65\x76\x72\x75\xa6\x41\xf7\x48\x37\x69\x53\x5d\xdc\x3e\x83\x91\x62\xcd\x83\xeb\x6d\x64\x64\x9a\x5d\x3b\x5f\x12\x7a\x6f\x54\x2e\x65\xb3\xc1\x8f\xdb\xdb\xac\xf7\x39\xa9\x5b\x6a\x46\x07\xc6\x68\x73\x14\x9d\x3b\x68\x46\xd1\xce\x56\xe3\xdc\xfe\xdb\xd8\xbf\x55\xe5\xbf\x85\x9a\x5e\xdb\xcb\xe7\x32\x77\x7c\x85\x6f\x47\xac\xd7\xf4\x80\x2a\x6a\x92\x2d\x41\xe7\xc8\xb7\x76\xba\x8d\x7b\xff\x87\xf5\x7b\xbd\x9e\xc7\xb7\x4d\xc8\xc3\x8b\x3f\x01\x00\x00\xff\xff\x4f\xa7\xa4\xe9\x05\x0a\x00\x00") func staticJsGottyJsBytes() ([]byte, error) { return bindataRead( @@ -126,7 +126,7 @@ func staticJsGottyJs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "static/js/gotty.js", size: 2525, mode: os.FileMode(436), modTime: time.Unix(1440919623, 0)} + info := bindataFileInfo{name: "static/js/gotty.js", size: 2565, mode: os.FileMode(436), modTime: time.Unix(1441003850, 0)} a := &asset{bytes: bytes, info: info} return a, nil } diff --git a/resources/gotty.js b/resources/gotty.js index b2293e5..5e10a9e 100644 --- a/resources/gotty.js +++ b/resources/gotty.js @@ -10,6 +10,8 @@ var term; ws.onopen = function(event) { + ws.send(gotty_auth_token); + hterm.defaultStorage = new lib.Storage.Local(); hterm.defaultStorage.clear(); diff --git a/resources/index.html b/resources/index.html index b33ff9f..5212a47 100644 --- a/resources/index.html +++ b/resources/index.html @@ -8,6 +8,7 @@
+