From fb20de03188b37b5c5d6b4109ab63df76ec27d82 Mon Sep 17 00:00:00 2001 From: Andrew Burke <31974658+atburke@users.noreply.github.com> Date: Thu, 2 Dec 2021 12:48:27 -0800 Subject: [PATCH 1/3] Clear web terminal when session ends (#8850) This change clears the screen when an ssh session ends (only in FIPS mode). Note: This doesn't currently do anything in `tsh` on Windows since BoringCrypto isn't supported, but once it is supported, the behavior will match Unix and web. Co-authored-by: Grzegorz Co-authored-by: Russell Jones --- lib/client/session.go | 24 +++++++++ lib/client/terminal/terminal_common.go | 69 ++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 lib/client/terminal/terminal_common.go diff --git a/lib/client/session.go b/lib/client/session.go index bf08586fefebc..658a61d472b0c 100644 --- a/lib/client/session.go +++ b/lib/client/session.go @@ -26,6 +26,7 @@ import ( "os" "os/signal" "strings" + "sync" "syscall" "time" @@ -68,6 +69,10 @@ type NodeSession struct { // this session. It's also used to wait for everyone to close closer *utils.CloseBroadcaster + // closeWait is used to wait for cleanup-related goroutines created by + // this session to close. + closeWait *sync.WaitGroup + ExitMsg string enableEscapeSequences bool @@ -108,6 +113,7 @@ func newSession(client *NodeClient, stderr: stderr, namespace: client.Namespace, closer: utils.NewCloseBroadcaster(), + closeWait: &sync.WaitGroup{}, enableEscapeSequences: enableEscapeSequences, } // if we're joining an existing session, we need to assume that session's @@ -140,6 +146,24 @@ func newSession(client *NodeClient, ns.id = session.ID(sid) } ns.env[sshutils.SessionEnvVar] = string(ns.id) + + // Close the Terminal when finished. + ns.closeWait.Add(1) + go func() { + defer ns.closeWait.Done() + + <-ns.closer.C + if isFIPS() { + // \x1b[3J - clears scrollback (it is needed at least for the Mac terminal) - + // https://newbedev.com/how-do-i-reset-the-scrollback-in-the-terminal-via-a-shell-command + // \x1b\x63 - clears current screen - same as '\0033\0143' from https://superuser.com/a/123007 + const resetPattern = "\x1b[3J\x1b\x63\n" + if _, err := ns.stdout.Write([]byte(resetPattern)); err != nil { + log.Warnf("Failed to clear screen: %v.", err) + } + } + }() + return ns, nil } diff --git a/lib/client/terminal/terminal_common.go b/lib/client/terminal/terminal_common.go new file mode 100644 index 0000000000000..bb78fedf43368 --- /dev/null +++ b/lib/client/terminal/terminal_common.go @@ -0,0 +1,69 @@ +/* +Copyright 2021 Gravitational, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package terminal + +import ( + "sync" + + "github.com/gravitational/teleport" + "github.com/gravitational/trace" + "github.com/sirupsen/logrus" +) + +var log = logrus.WithFields(logrus.Fields{ + trace.Component: teleport.ComponentClient, +}) + +// ResizeEvent is emitted when a terminal window is resized. +type ResizeEvent struct{} + +// StopEvent is emitted when the user sends a SIGSTOP +type StopEvent struct{} + +type signalEmitter struct { + subscribers []chan interface{} + subscribersMutex sync.Mutex +} + +// Subscribe creates a channel that will receive terminal events. +func (e *signalEmitter) Subscribe() chan interface{} { + e.subscribersMutex.Lock() + defer e.subscribersMutex.Unlock() + + ch := make(chan interface{}) + e.subscribers = append(e.subscribers, ch) + + return ch +} + +func (e *signalEmitter) writeEvent(event interface{}) { + e.subscribersMutex.Lock() + defer e.subscribersMutex.Unlock() + + for _, sub := range e.subscribers { + sub <- event + } +} + +func (e *signalEmitter) clearSubscribers() { + e.subscribersMutex.Lock() + defer e.subscribersMutex.Unlock() + + for _, ch := range e.subscribers { + close(ch) + } + e.subscribers = e.subscribers[:0] +} From 43edf1c7e1e5a6200b9ae05fd7d1bb01ee3b7ba6 Mon Sep 17 00:00:00 2001 From: Andrew Burke Date: Thu, 9 Dec 2021 14:15:58 -0800 Subject: [PATCH 2/3] Fix fips check and re-add close waitgroup --- lib/client/session.go | 4 ++++ lib/modules/modules.go | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/client/session.go b/lib/client/session.go index 658a61d472b0c..b12343cd87a91 100644 --- a/lib/client/session.go +++ b/lib/client/session.go @@ -289,6 +289,7 @@ func (ns *NodeSession) interactiveSession(callback interactiveCallback) error { } // wait for the session to end <-ns.closer.C + ns.closeWait.Wait() return nil } @@ -632,5 +633,8 @@ func (ns *NodeSession) Close() error { if ns.closer != nil { ns.closer.Close() } + if ns.closeWait != nil { + ns.closeWait.Wait() + } return nil } diff --git a/lib/modules/modules.go b/lib/modules/modules.go index 37b8a905e0842..358b7c5c00163 100644 --- a/lib/modules/modules.go +++ b/lib/modules/modules.go @@ -19,7 +19,9 @@ limitations under the License. package modules import ( + "crypto/sha256" "fmt" + "reflect" "runtime" "sync" @@ -118,7 +120,11 @@ func (p *defaultModules) Features() Features { // IsBoringBinary checks if the binary was compiled with BoringCrypto. func (p *defaultModules) IsBoringBinary() bool { - return false + // Check the package name for one of the boring primitives, if the package + // path is from BoringCrypto, we know this binary was compiled against the + // dev.boringcrypto branch of Go. + hash := sha256.New() + return reflect.TypeOf(hash).Elem().PkgPath() == "crypto/internal/boring" } var ( From fe1555e24a6d7712eec0fa26141059ed2de6413e Mon Sep 17 00:00:00 2001 From: Andrew Burke Date: Thu, 9 Dec 2021 14:47:10 -0800 Subject: [PATCH 3/3] Remove terminal_common.go --- lib/client/terminal/terminal_common.go | 69 -------------------------- 1 file changed, 69 deletions(-) delete mode 100644 lib/client/terminal/terminal_common.go diff --git a/lib/client/terminal/terminal_common.go b/lib/client/terminal/terminal_common.go deleted file mode 100644 index bb78fedf43368..0000000000000 --- a/lib/client/terminal/terminal_common.go +++ /dev/null @@ -1,69 +0,0 @@ -/* -Copyright 2021 Gravitational, Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package terminal - -import ( - "sync" - - "github.com/gravitational/teleport" - "github.com/gravitational/trace" - "github.com/sirupsen/logrus" -) - -var log = logrus.WithFields(logrus.Fields{ - trace.Component: teleport.ComponentClient, -}) - -// ResizeEvent is emitted when a terminal window is resized. -type ResizeEvent struct{} - -// StopEvent is emitted when the user sends a SIGSTOP -type StopEvent struct{} - -type signalEmitter struct { - subscribers []chan interface{} - subscribersMutex sync.Mutex -} - -// Subscribe creates a channel that will receive terminal events. -func (e *signalEmitter) Subscribe() chan interface{} { - e.subscribersMutex.Lock() - defer e.subscribersMutex.Unlock() - - ch := make(chan interface{}) - e.subscribers = append(e.subscribers, ch) - - return ch -} - -func (e *signalEmitter) writeEvent(event interface{}) { - e.subscribersMutex.Lock() - defer e.subscribersMutex.Unlock() - - for _, sub := range e.subscribers { - sub <- event - } -} - -func (e *signalEmitter) clearSubscribers() { - e.subscribersMutex.Lock() - defer e.subscribersMutex.Unlock() - - for _, ch := range e.subscribers { - close(ch) - } - e.subscribers = e.subscribers[:0] -}