Skip to content

Commit 0e52ee1

Browse files
committed
update gokit, start using structured logging and improved CLI primitives
1 parent 1dfaec8 commit 0e52ee1

File tree

5 files changed

+101
-1195
lines changed

5 files changed

+101
-1195
lines changed

cmd/function22/genkey.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package main
22

33
import (
4+
"context"
45
"crypto/ed25519"
56
"crypto/rand"
67
"fmt"
78
"os"
89

910
"github.com/ScaleFT/sshkeys"
11+
"github.com/function61/gokit/app/cli"
1012
"github.com/function61/gokit/os/osutil"
1113
"github.com/spf13/cobra"
1214
)
@@ -16,9 +18,9 @@ func generateHostKeyEntrypoint() *cobra.Command {
1618
Use: "host-key-generate",
1719
Short: "Generates the host key at " + defaultHostKeyFile,
1820
Args: cobra.NoArgs,
19-
Run: func(_ *cobra.Command, _ []string) {
20-
osutil.ExitIfError(generateHostKey())
21-
},
21+
Run: cli.WrapRun(func(_ context.Context, _ []string) error {
22+
return generateHostKey()
23+
}),
2224
}
2325
}
2426

cmd/function22/helpers.go

Lines changed: 32 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"syscall"
1010
"unsafe"
1111

12+
"github.com/function61/gokit/app/cli"
1213
"github.com/function61/gokit/os/osutil"
1314
"github.com/function61/gokit/os/systemdinstaller"
1415
gliderssh "github.com/gliderlabs/ssh"
@@ -24,48 +25,46 @@ func installEntrypoint() *cobra.Command {
2425
Use: "install",
2526
Short: "Make the server start on system startup",
2627
Args: cobra.NoArgs,
27-
Run: func(_ *cobra.Command, _ []string) {
28-
osutil.ExitIfError(func() error {
29-
if validateHostKey {
30-
hostKeyExists, err := osutil.Exists(defaultHostKeyFile)
31-
if err != nil {
32-
return err
33-
}
34-
35-
if !hostKeyExists { // pro-tip
36-
return errors.New("host key doesn't exist. create it by running $ " + os.Args[0] + " host-key-generate")
37-
}
28+
Run: cli.WrapRun(func(_ context.Context, _ []string) error {
29+
if validateHostKey {
30+
hostKeyExists, err := osutil.Exists(defaultHostKeyFile)
31+
if err != nil {
32+
return err
3833
}
3934

40-
if allowedUsers == "" {
41-
return errors.New("you need to specify --allowed-users=")
35+
if !hostKeyExists { // pro-tip
36+
return errors.New("host key doesn't exist. create it by running $ " + os.Args[0] + " host-key-generate")
4237
}
38+
}
4339

44-
options := []systemdinstaller.Option{
45-
systemdinstaller.Docs(
46-
"https://github.com/function61/function22",
47-
"https://function61.com/"),
48-
systemdinstaller.Env("SSH_ALLOWED_USERS", allowedUsers),
49-
}
40+
if allowedUsers == "" {
41+
return errors.New("you need to specify --allowed-users=")
42+
}
5043

51-
if interfaceName != "" {
52-
options = append(
53-
options,
54-
systemdinstaller.Env("SSH_LISTEN_INTERFACE", interfaceName),
55-
systemdinstaller.WaitNetworkInterface(interfaceName))
56-
}
44+
options := []systemdinstaller.Option{
45+
systemdinstaller.Docs(
46+
"https://github.com/function61/function22",
47+
"https://function61.com/"),
48+
systemdinstaller.Env("SSH_ALLOWED_USERS", allowedUsers),
49+
}
5750

58-
service := systemdinstaller.Service("function22", tagline, options...)
51+
if interfaceName != "" {
52+
options = append(
53+
options,
54+
systemdinstaller.Env("SSH_LISTEN_INTERFACE", interfaceName),
55+
systemdinstaller.WaitNetworkInterface(interfaceName))
56+
}
5957

60-
if err := systemdinstaller.Install(service); err != nil {
61-
return err
62-
}
58+
service := systemdinstaller.Service("function22", tagline, options...)
59+
60+
if err := systemdinstaller.Install(service); err != nil {
61+
return err
62+
}
6363

64-
fmt.Println(systemdinstaller.EnableAndStartCommandHints(service))
64+
fmt.Println(systemdinstaller.EnableAndStartCommandHints(service))
6565

66-
return nil
67-
}())
68-
},
66+
return nil
67+
}),
6968
}
7069

7170
cmd.Flags().StringVarP(&allowedUsers, "allowed-users", "", allowedUsers, "Users allowed for SSH access: 'user1,user2'")

cmd/function22/main.go

Lines changed: 24 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"bufio"
55
"context"
66
"fmt"
7-
"log"
87
"log/slog"
98
"net"
109
"os"
@@ -16,9 +15,8 @@ import (
1615

1716
"github.com/creack/pty"
1817
"github.com/function61/function22/pkg/linuxuser"
19-
"github.com/function61/gokit/app/dynversion"
18+
"github.com/function61/gokit/app/cli"
2019
"github.com/function61/gokit/io/bidipipe"
21-
"github.com/function61/gokit/log/logex"
2220
"github.com/function61/gokit/os/osutil"
2321
gliderssh "github.com/gliderlabs/ssh"
2422
"github.com/spf13/cobra"
@@ -31,27 +29,22 @@ const (
3129

3230
func main() {
3331
app := &cobra.Command{
34-
Use: os.Args[0],
35-
Short: tagline,
36-
Version: dynversion.Version,
37-
Args: cobra.NoArgs,
38-
Run: func(_ *cobra.Command, args []string) {
39-
rootLogger := logex.StandardLogger()
40-
41-
osutil.ExitIfError(logic(
42-
osutil.CancelOnInterruptOrTerminate(rootLogger),
43-
true,
44-
rootLogger))
45-
},
32+
Short: tagline,
33+
Args: cobra.NoArgs,
34+
Run: cli.WrapRun(func(ctx context.Context, _ []string) error {
35+
return logic(ctx)
36+
}),
4637
}
4738

39+
cli.AddLogLevelControls(app.Flags())
40+
4841
app.AddCommand(generateHostKeyEntrypoint())
4942
app.AddCommand(installEntrypoint())
5043

51-
osutil.ExitIfError(app.Execute())
44+
cli.Execute(app)
5245
}
5346

54-
func logic(ctx context.Context, verbose bool, logger *log.Logger) error {
47+
func logic(ctx context.Context) error {
5548
listenInterface := os.Getenv("SSH_LISTEN_INTERFACE")
5649

5750
allowedUsersSerialized, err := osutil.GetenvRequired("SSH_ALLOWED_USERS") // "user1,user2"
@@ -89,8 +82,8 @@ func logic(ctx context.Context, verbose bool, logger *log.Logger) error {
8982

9083
if err := gliderssh.Serve(sshPortListener, func(s gliderssh.Session) {
9184
// user now definitely exists in *knownUsers*
92-
if err := s.Exit(handleSSHConnection(s, *knownUsers[s.User()], verbose, logger)); err != nil {
93-
logger.Printf("session.Exit(): %v", err)
85+
if err := s.Exit(handleSSHConnection(s, *knownUsers[s.User()])); err != nil {
86+
slog.Error("session.Exit()", "err", err)
9487
}
9588
},
9689
gliderssh.HostKeyFile(defaultHostKeyFile),
@@ -99,7 +92,7 @@ func logic(ctx context.Context, verbose bool, logger *log.Logger) error {
9992

10093
account, found := knownUsers[username]
10194
if !found {
102-
logger.Printf("login attempt for unknown user: %s", username)
95+
slog.Warn("login attempt for unknown user", "username", username)
10396
return false
10497
}
10598

@@ -111,7 +104,7 @@ func logic(ctx context.Context, verbose bool, logger *log.Logger) error {
111104
}),
112105
gliderssh.PublicKeyAuth(func(ctx gliderssh.Context, userKey gliderssh.PublicKey) bool {
113106
if _, allowed := knownUsers[ctx.User()]; !allowed {
114-
logger.Printf("login attempt for unknown user: %s", ctx.User())
107+
slog.Warn("login attempt for unknown user", "username", ctx.User())
115108
return false
116109
}
117110

@@ -121,7 +114,7 @@ func logic(ctx context.Context, verbose bool, logger *log.Logger) error {
121114
if os.IsNotExist(err) { // user simply doesn't have them
122115
return false
123116
} else {
124-
logger.Printf("error reading authorized_keys: %v", err)
117+
slog.Error("error reading authorized_keys", "err", err)
125118
return false
126119
}
127120
}
@@ -131,7 +124,7 @@ func logic(ctx context.Context, verbose bool, logger *log.Logger) error {
131124
for authorizedKeys.Scan() {
132125
authorizedKey, _, _, _, err := gliderssh.ParseAuthorizedKey(authorizedKeys.Bytes())
133126
if err != nil {
134-
logger.Printf("ParseAuthorizedKey: %v", err)
127+
slog.Error("ParseAuthorizedKey", "err", err)
135128
return false
136129
}
137130

@@ -140,7 +133,7 @@ func logic(ctx context.Context, verbose bool, logger *log.Logger) error {
140133
}
141134
}
142135
if err := authorizedKeys.Err(); err != nil {
143-
logger.Printf("error scanning: %v", err)
136+
slog.Error("scanning", "err", err)
144137
return false
145138
}
146139

@@ -158,18 +151,16 @@ func logic(ctx context.Context, verbose bool, logger *log.Logger) error {
158151
return nil
159152
}
160153

161-
func handleSSHConnection(s gliderssh.Session, account linuxuser.Account, verbose bool, logger *log.Logger) int {
162-
if verbose {
163-
user := s.User()
154+
func handleSSHConnection(s gliderssh.Session, account linuxuser.Account) int {
155+
user := s.User()
164156

165-
tcpAddress := s.RemoteAddr().(*net.TCPAddr)
157+
tcpAddress := s.RemoteAddr().(*net.TCPAddr)
166158

167-
logger.Printf("new session for %q from %v", user, tcpAddress)
168-
defer logger.Printf("closing session for %q from %v", user, tcpAddress)
169-
}
159+
slog.Debug("new session", "user", user, "tcpAddress", tcpAddress)
160+
defer slog.Debug("closing session", "user", user, "tcpAddress", tcpAddress)
170161

171162
if subsys := s.Subsystem(); subsys != "" { // what does this do? AFAIK SCP is a subsystem but even it doesn't set it?
172-
logger.Printf("unsupported subsystem specified: %s", subsys)
163+
slog.Error("unsupported subsystem specified", "subsys", subsys)
173164
fmt.Fprint(s, "unsupported subsystem specified\n")
174165
return 1
175166
}
@@ -256,7 +247,7 @@ func handleSSHConnection(s gliderssh.Session, account linuxuser.Account, verbose
256247
if isPty {
257248
terminal, err := pty.Start(cmd)
258249
if err != nil {
259-
logger.Printf("running shell: %v", err)
250+
slog.Error("starting shell", "err", err)
260251
return 1
261252
}
262253
defer terminal.Close()

go.mod

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,28 @@
11
module github.com/function61/function22
22

3-
go 1.16
3+
go 1.21
4+
5+
toolchain go1.21.5
46

57
require (
68
github.com/GehirnInc/crypt v0.0.0-20230320061759-8cc1b52080c5
79
github.com/ScaleFT/sshkeys v0.0.0-20200327173127-6142f742bca5
810
github.com/creack/pty v1.1.17
9-
github.com/function61/gokit v0.0.0-20220102105228-f5a0195f3643
11+
github.com/function61/gokit v0.0.0-20241219151907-f0ce2a6aac07
1012
github.com/gliderlabs/ssh v0.3.3
11-
github.com/spf13/cobra v1.2.1
12-
inet.af/netaddr v0.0.0-20211027220019-c74959edd3b6
13-
tailscale.com v1.18.1
13+
github.com/spf13/cobra v1.6.1
14+
)
15+
16+
require (
17+
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
18+
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a // indirect
19+
github.com/inconshreveable/mousetrap v1.0.1 // indirect
20+
github.com/lmittmann/tint v1.0.5 // indirect
21+
github.com/mattn/go-isatty v0.0.20 // indirect
22+
github.com/pkg/xattr v0.4.4 // indirect
23+
github.com/spf13/pflag v1.0.5 // indirect
24+
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa // indirect
25+
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
26+
golang.org/x/sys v0.6.0 // indirect
27+
golang.org/x/term v0.0.0-20210503060354-a79de5458b56 // indirect
1428
)

0 commit comments

Comments
 (0)