Skip to content

Commit

Permalink
Merge pull request #4 from qnkhuat/password
Browse files Browse the repository at this point in the history
Add passcode
  • Loading branch information
qnkhuat authored Jan 31, 2022
2 parents e6f26da + 562c6a1 commit 201e0bd
Show file tree
Hide file tree
Showing 10 changed files with 280 additions and 80 deletions.
21 changes: 11 additions & 10 deletions cli/cmd/termishare/termishare.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,32 +20,33 @@ func main() {

// if termishare get an argument that are not a flag, use it as the client
if len(args) == 1 {
logging.Config("/tmp/termishare.log", "REMOTE CLIENT: ")
// use as a remote client
logging.Config("/tmp/termishare.log", "REMOTE CLIENT: ")

rc := termishare.NewRemoteClient()

re := regexp.MustCompile(`^((http|https):\/\/[^\s/]+)\/([^\s/]+)*`)
matches := re.FindSubmatch([]byte(args[0]))
// url with template http://server.com/sessionID
serverURLRe := regexp.MustCompile(`^((http|https):\/\/[^\s/]+)\/([^\s/]+)*`)
matches := serverURLRe.FindSubmatch([]byte(args[0]))
if len(matches) == 4 {
// url with template http://server.com/sessionID
rc.Connect(string(matches[1]), string(matches[3]))
} else if !strings.Contains(args[0], "/") {
// guessing we're passed with only sessionID
// Use default server with a sessionID
rc.Connect(*server, args[0])
} else {
fmt.Println("Failed to parse arguments")
}
return
} else {
logging.Config("/tmp/termishare.log", "TERMISHARE: ")
// use as a host
logging.Config("/tmp/termishare.log", "TERMISHARE: ")
sessionID := os.Getenv(cfg.TERMISHARE_ENVKEY_SESSIONID)

if sessionID != "" {
fmt.Printf("This terminal is already being shared at: %s\n", termishare.GetClientURL(*server, sessionID))
} else {
ts := termishare.New()
ts.Start(*server, *noTurn)
return
}
ts := termishare.New(*noTurn)
ts.Start(*server)
return
}
}
3 changes: 3 additions & 0 deletions cli/internal/cfg/termishare.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ const (
TERMISHARE_WEBRTC_DATA_CHANNEL = "termishare" // lable name of webrtc data channel to exchange byte data
TERMISHARE_WEBRTC_CONFIG_CHANNEL = "config" // lable name of webrtc config channel to exchange config
TERMISHARE_WEBSOCKET_HOST_ID = "host" // ID of message sent by the host

TERMISHARE_VERSION = "0.0.4"
SUPPORTED_VERSION = "0.0.4" // the oldest termishare version of client that the host could support
)

var TERMISHARE_ICE_SERVER_STUNS = []webrtc.ICEServer{{URLs: []string{"stun:stun.l.google.com:19302", "stun:stun1.l.google.com:19302"}}}
Expand Down
22 changes: 19 additions & 3 deletions cli/pkg/message/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import (
type MType string

const (
TRTCWillYouMarryMe MType = "WillYouMarryMe" // Offer
TRTCYes MType = "Yes" // Answer
TRTCKiss MType = "Kiss" // Candidate
// TODO refactor to make these message type as part of message
// we probably only need RTC, Control, Connect types
TRTCOffer MType = "Offer"
TRTCAnswer MType = "Answer"
TRTCCandidate MType = "Candidate"

TTermWinsize MType = "Winsize" // Update winsize

Expand All @@ -18,6 +20,20 @@ const (
TTermRefresh MType = "Refresh"

TWSPing MType = "Ping"

// Whether or not a connection require a passcode
// when connect, client will first send a connect message
// server response with whether or not client needs to provide a passcode
TCConnect = "Connect"
TCRequirePasscode = "RequirePasscode"
TCNoPasscode = "NoPasscode"
// message to wrap passcode
TCPasscode = "Passcode"
// connection's response
TCAuthenticated = "Authenticated"
TCUnauthenticated = "Unauthenticated"

TCUnsupportedVersion = "UnsupportedVersion"
)

type Wrapper struct {
Expand Down
6 changes: 4 additions & 2 deletions cli/pkg/pty/pty.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
Wrapper around the pty
Used to control (start, stop) and communicate with the terminal
Used to control (start, stop) and communicate with the tty
*/

// Most the code are taken from : https://github.com/elisescu/tty-share/blob/master/pty_master.go
Expand Down Expand Up @@ -93,7 +93,9 @@ func (pty *Pty) Stop() error {
}

func (pty *Pty) Restore() {
term.Restore(0, pty.terminalInitState)
if pty.terminalInitState != nil {
term.Restore(0, pty.terminalInitState)
}
}

func (pty *Pty) Refresh() {
Expand Down
120 changes: 85 additions & 35 deletions cli/pkg/termishare/remoteClient.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"fmt"
"log"
"os"
"strings"
"time"

ptyDevice "github.com/creack/pty"
Expand Down Expand Up @@ -42,36 +43,30 @@ type RemoteClient struct {
thisCols uint16
}
muteDisplay bool
connected bool
}

func NewRemoteClient() *RemoteClient {
return &RemoteClient{
pty: pty.New(),
clientID: uuid.NewString(),
done: make(chan bool),
muteDisplay: false,
connected: false,
done: make(chan bool),
}
}

func (rc *RemoteClient) Connect(server string, sessionID string) {
log.Printf("Start")
wsURL := GetWSURL(server, sessionID)
fmt.Printf("Connecting to : %s\n", wsURL)
fmt.Println("Press 'Ctrl-x + Ctrl-x' to exit")

fmt.Printf("Press Enter to continue!\n")
bufio.NewReader(os.Stdin).ReadString('\n')
fmt.Printf("Connecting to: %s\n", wsURL)

wsConn, err := NewWebSocketConnection(wsURL)
if err != nil {
log.Printf("Failed to connect to singaling server: %s", err)
rc.Stop("Failed to connect to signaling server")
}
go wsConn.Start()
rc.wsConn = wsConn

// will stop stdin from piping to stdout
rc.pty.MakeRaw()
defer rc.pty.Restore()

winsize, err := pty.GetWinsize(0)
if err != nil {
Expand Down Expand Up @@ -162,33 +157,45 @@ func (rc *RemoteClient) Connect(server string, sessionID string) {
}

msg := message.Wrapper{
Type: message.TRTCKiss,
Type: message.TRTCCandidate,
Data: string(candidate),
}

rc.sendWebsocket(msg)
rc.writeWebsocket(msg)
})

// send offer
offer, err := peerConn.CreateOffer(nil)
if err != nil {
log.Printf("Failed to create offer :%s", err)
rc.Stop("Failed to connect to termishare session")
}
// block until handleWebSocketMessage set rc.connected to true
rc.wsConn = wsConn
rc.writeWebsocket(message.Wrapper{
Type: message.TCConnect,
Data: cfg.TERMISHARE_VERSION})
for {
if rc.connected {
break
}

err = peerConn.SetLocalDescription(offer)
if err != nil {
log.Printf("Failed to set local description: %s", err)
rc.Stop("Failed to connect to termishare session")
}
msg, ok := <-rc.wsConn.In
if !ok {
log.Printf("Failed to read websocket message")
break
}

offerByte, _ := json.Marshal(offer)
payload := message.Wrapper{
Type: message.TRTCWillYouMarryMe,
Data: string(offerByte),
// only read message sent from the host
if msg.From != cfg.TERMISHARE_WEBSOCKET_HOST_ID {
log.Printf("Skip message :%v", msg)
}

err := rc.handleWebSocketMessage(msg)
if err != nil {
log.Printf("Failed to handle message: %v, with error: %s", msg, err)
break
}
}

rc.sendWebsocket(payload)
// should be connected by now
fmt.Println("Press 'Ctrl-x + Ctrl-x' to exit")
rc.pty.MakeRaw()
defer rc.pty.Restore()

// Read from stdin and send to the host
stdinReader := bufio.NewReaderSize(os.Stdin, 1)
Expand Down Expand Up @@ -239,21 +246,64 @@ func (rc *RemoteClient) Connect(server string, sessionID string) {
return
}

func (rc *RemoteClient) sendOffer() {

offer, err := rc.peerConn.CreateOffer(nil)
if err != nil {
log.Printf("Failed to create offer :%s", err)
rc.Stop("Failed to connect to termishare session")
}

err = rc.peerConn.SetLocalDescription(offer)
if err != nil {
log.Printf("Failed to set local description: %s", err)
rc.Stop("Failed to connect to termishare session")
}

offerByte, _ := json.Marshal(offer)
payload := message.Wrapper{
Type: message.TRTCOffer,
Data: string(offerByte),
}

rc.writeWebsocket(payload)
}

func (rc *RemoteClient) handleWebSocketMessage(msg message.Wrapper) error {
switch msgType := msg.Type; msgType {
// offer
case message.TRTCWillYouMarryMe:
return fmt.Errorf("Remote client shouldn't receive WillYouMarryMe message")

case message.TRTCYes:
case message.TCUnsupportedVersion:
rc.Stop(fmt.Sprintf("The host require termishare version: %s and you're running %s. Please upgrade it! (github.com/qnkhuat/termishare)", msg.Data, cfg.TERMISHARE_VERSION))

case message.TCUnauthenticated:
fmt.Printf("Incorrect passcode!\n")
fallthrough
case message.TCRequirePasscode:
fmt.Printf("Passcode: ")
passcode, _ := bufio.NewReader(os.Stdin).ReadString('\n')
passcode = strings.TrimSpace(passcode)
resp := message.Wrapper{
Type: message.TCPasscode,
Data: passcode,
}
rc.writeWebsocket(resp)

case message.TCNoPasscode, message.TCAuthenticated:
rc.connected = true
rc.sendOffer()

case message.TRTCOffer:
return fmt.Errorf("Remote client shouldn't receive Offer message")

case message.TRTCAnswer:
answer := webrtc.SessionDescription{}
if err := json.Unmarshal([]byte(msg.Data.(string)), &answer); err != nil {
return err
}

rc.peerConn.SetRemoteDescription(answer)

case message.TRTCKiss:
case message.TRTCCandidate:
candidate := webrtc.ICECandidateInit{}
if err := json.Unmarshal([]byte(msg.Data.(string)), &candidate); err != nil {
return fmt.Errorf("Failed to unmarshall icecandidate: %s", err)
Expand Down Expand Up @@ -337,7 +387,7 @@ func (rc *RemoteClient) sendConfig(msg message.Wrapper) error {
}
}

func (rc *RemoteClient) sendWebsocket(msg message.Wrapper) error {
func (rc *RemoteClient) writeWebsocket(msg message.Wrapper) error {
msg.To = cfg.TERMISHARE_WEBSOCKET_HOST_ID
msg.From = rc.clientID
if rc.wsConn == nil {
Expand Down
Loading

0 comments on commit 201e0bd

Please sign in to comment.