Merge branch 'master' into whitelist-command

This commit is contained in:
mik2k2 2021-12-22 14:07:46 +01:00
commit 89ee27d930
8 changed files with 71 additions and 47 deletions

View File

@ -43,4 +43,4 @@ release:
deploy: build/ssh-chat-linux_amd64.tgz
ssh -p 2022 ssh.chat tar xvz < build/ssh-chat-linux_amd64.tgz
@echo " --- Ready to deploy ---"
@echo "Run: ssh -p 2022 ssh.chat sudo systemctl restart ssh-chat"
@echo "Run: ssh -t -p 2022 ssh.chat sudo systemctl restart ssh-chat"

View File

@ -18,7 +18,9 @@ $ ssh ssh.chat
Please abide by our [project's Code of Conduct](https://github.com/shazow/ssh-chat/blob/master/CODE_OF_CONDUCT.md) while participating in chat.
The server's RSA key fingerprint is `MD5:e5:d5:d1:75:90:38:42:f6:c7:03:d7:d0:56:7d:6a:db` or `SHA256:HQDLlZsXL3t0lV5CHM0OXeZ5O6PcfHuzkS8cRbbTLBI`. If you see something different, you might be [MITM](https://en.wikipedia.org/wiki/Man-in-the-middle_attack)'d.
The host's public key is `ssh.chat ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKPrQofxXqoz2y9A7NFkkENt6iW8/mvpfes3RY/41Oyt` and the fingerprint is `SHA256:yoqMXkCysMTBsvhu2yRoMUl+EmZKlvkN+ZKmL3115xU` (as of 2021-10-13).
If you see something different, you might be [MITM](https://en.wikipedia.org/wiki/Man-in-the-middle_attack)'d.
(Apologies if the server is down, try again shortly.)

View File

@ -469,12 +469,13 @@ func InitCommands(c *Commands) {
msg.From().SetAway(awayMsg)
if awayMsg != "" {
room.Send(message.NewEmoteMsg("has gone away: "+awayMsg, msg.From()))
} else if !isAway {
room.Send(message.NewSystemMsg("Not away. Append a reason message to set away.", msg.From()))
} else {
room.Send(message.NewEmoteMsg("is back.", msg.From()))
return nil
}
return nil
if isAway {
room.Send(message.NewEmoteMsg("is back.", msg.From()))
return nil
}
return errors.New("not away. Append a reason message to set away")
},
})
@ -486,8 +487,9 @@ func InitCommands(c *Commands) {
if isAway {
msg.From().SetAway("")
room.Send(message.NewEmoteMsg("is back.", msg.From()))
return nil
}
return nil
return errors.New("must be away to be back")
},
})

View File

@ -25,10 +25,17 @@ func TestAwayCommands(t *testing.T) {
// expected output
IsUserAway bool
AwayMessage string
// expected state change
ExpectsError func(awayBefore bool) bool
}
awayStep := step{"/away snorkling", true, "snorkling"}
notAwayStep := step{"/away", false, ""}
backStep := step{"/back", false, ""}
neverError := func(_ bool) bool { return false }
// if the user was away before, then the error is expected
errorIfAwayBefore := func(awayBefore bool) bool { return awayBefore }
awayStep := step{"/away snorkling", true, "snorkling", neverError}
notAwayStep := step{"/away", false, "", errorIfAwayBefore}
backStep := step{"/back", false, "", errorIfAwayBefore}
steps := []step{awayStep, notAwayStep, backStep}
cases := [][]int{
@ -42,7 +49,12 @@ func TestAwayCommands(t *testing.T) {
for _, s := range []step{steps[c[0]], steps[c[1]], steps[c[2]]} {
msg, _ := message.NewPublicMsg(s.Msg, u).ParseCommand()
cmds.Run(room, *msg)
awayBeforeCommand, _, _ := u.GetAway()
err := cmds.Run(room, *msg)
if err != nil && s.ExpectsError(awayBeforeCommand) {
t.Fatalf("unexpected error running the command: %+v", err)
}
isAway, _, awayMsg := u.GetAway()
if isAway != s.IsUserAway {

View File

@ -26,16 +26,16 @@ var Version string = "dev"
// Options contains the flag options
type Options struct {
Admin string `long:"admin" description:"File of public keys who are admins."`
Bind string `long:"bind" description:"Host and port to listen on." default:"0.0.0.0:2022"`
Identity string `short:"i" long:"identity" description:"Private key to identify server with." default:"~/.ssh/id_rsa"`
Log string `long:"log" description:"Write chat log to this file."`
Motd string `long:"motd" description:"Optional Message of the Day file."`
Pprof int `long:"pprof" description:"Enable pprof http server for profiling."`
Verbose []bool `short:"v" long:"verbose" description:"Show verbose logging."`
Version bool `long:"version" description:"Print version and exit."`
Whitelist string `long:"whitelist" description:"Optional file of public keys who are allowed to connect."`
Passphrase string `long:"unsafe-passphrase" description:"Require an interactive passphrase to connect. Whitelist feature is more secure."`
Admin string `long:"admin" description:"File of public keys who are admins."`
Bind string `long:"bind" description:"Host and port to listen on." default:"0.0.0.0:2022"`
Identity []string `short:"i" long:"identity" description:"Private key to identify server with." default:"~/.ssh/id_rsa"`
Log string `long:"log" description:"Write chat log to this file."`
Motd string `long:"motd" description:"Optional Message of the Day file."`
Pprof int `long:"pprof" description:"Enable pprof http server for profiling."`
Verbose []bool `short:"v" long:"verbose" description:"Show verbose logging."`
Version bool `long:"version" description:"Print version and exit."`
Whitelist string `long:"whitelist" description:"Optional file of public keys who are allowed to connect."`
Passphrase string `long:"unsafe-passphrase" description:"Require an interactive passphrase to connect. Whitelist feature is more secure."`
}
const extraHelp = `There are hidden options and easter eggs in ssh-chat. The source code is a good
@ -100,25 +100,28 @@ func main() {
message.SetLogger(os.Stderr)
}
privateKeyPath := options.Identity
if strings.HasPrefix(privateKeyPath, "~/") {
user, err := user.Current()
if err == nil {
privateKeyPath = strings.Replace(privateKeyPath, "~", user.HomeDir, 1)
}
}
signer, err := ReadPrivateKey(privateKeyPath)
if err != nil {
fail(3, "Failed to read identity private key: %v\n", err)
}
auth := sshchat.NewAuth()
config := sshd.MakeAuth(auth)
config.AddHostKey(signer)
config.ServerVersion = "SSH-2.0-Go ssh-chat"
// FIXME: Should we be using config.NoClientAuth = true by default?
for _, privateKeyPath := range options.Identity {
if strings.HasPrefix(privateKeyPath, "~/") {
user, err := user.Current()
if err == nil {
privateKeyPath = strings.Replace(privateKeyPath, "~", user.HomeDir, 1)
}
}
signer, err := ReadPrivateKey(privateKeyPath)
if err != nil {
fail(3, "Failed to read identity private key: %v\n", err)
}
config.AddHostKey(signer)
fmt.Printf("Added server identity: %s\n", sshd.Fingerprint(signer.PublicKey()))
}
s, err := sshd.ListenSSH(options.Bind, config)
if err != nil {
fail(4, "Failed to listen on socket: %v\n", err)

6
go.mod
View File

@ -4,11 +4,11 @@ require (
github.com/alexcesaro/log v0.0.0-20150915221235-61e686294e58
github.com/jessevdk/go-flags v1.5.0
github.com/shazow/rateio v0.0.0-20200113175441-4461efc8bdc4
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20210324051608-47abb6519492
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881
golang.org/x/term v0.0.0-20210317153231-de623e64d2a6
golang.org/x/text v0.3.5
golang.org/x/text v0.3.6
)
go 1.13

17
go.sum
View File

@ -4,19 +4,20 @@ github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LF
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
github.com/shazow/rateio v0.0.0-20200113175441-4461efc8bdc4 h1:zwQ1HBo5FYwn1ksMd19qBCKO8JAWE9wmHivEpkw/DvE=
github.com/shazow/rateio v0.0.0-20200113175441-4461efc8bdc4/go.mod h1:vt2jWY/3Qw1bIzle5thrJWucsLuuX9iUNnp20CqCciI=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e h1:MUP6MR3rJ7Gk9LEia0LP2ytiH6MuCfs7qYz+47jGdD8=
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210324051608-47abb6519492 h1:Paq34FxTluEPvVyayQqMPgHm+vTOrIifmcYxFBx9TLg=
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881 h1:TyHqChC80pFkXWraUUf6RuB5IqFdQieMLwwCJokV2pc=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210317153231-de623e64d2a6 h1:EC6+IGYTjPpRfv9a2b/6Puw0W+hLtAhkV1tPsXhutqs=
golang.org/x/term v0.0.0-20210317153231-de623e64d2a6/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -264,6 +264,10 @@ func (t *Terminal) moveCursorToPos(pos int) {
return
}
if pos > len(t.line) {
pos = len(t.line)
}
x := visualLength(t.prompt) + visualLength(t.line[:pos])
y := x / t.termWidth
x = x % t.termWidth