diff --git a/Dockerfile b/Dockerfile index 6ad94c3..bb75f46 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM debian:bullseye as build +FROM debian:bookworm as build RUN apt update && apt install -y git golang ca-certificates diff --git a/Makefile b/Makefile index a409f1c..9538e10 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,6 @@ NAMESPACE ?= hashbangctl +UID ?= $(shell id -u) +GID ?= $(shell id -g) .PHONY: build build: @@ -33,8 +35,8 @@ test: docker-build docker-build-test docker-stop docker-start --hostname=$(NAMESPACE)-test \ --name $(NAMESPACE)-test \ --network=userdb \ - --env UID=$(shell id -u) \ - --env GID=$(shell id -g) \ + --env UID=$(UID) \ + --env GID=$(GID) \ --env CONTAINER=$(NAMESPACE) \ --env PGPASSWORD=test_password \ --env PGHOST=userdb-postgres \ @@ -52,8 +54,8 @@ test-shell: docker-build docker-build-test docker-stop docker-start --hostname=$(NAMESPACE)-test \ --name $(NAMESPACE)-test \ --network=userdb \ - --env UID=$(shell id -u) \ - --env GID=$(shell id -g) \ + --env UID=$(UID) \ + --env GID=$(GID) \ --env CONTAINER=$(NAMESPACE) \ --env PGPASSWORD=test_password \ --env PGHOST=userdb-postgres \ @@ -79,7 +81,7 @@ initdb: .PHONY: docker-logs docker-logs: - scripts/docker-logs $(NAMESPACE) userdb-postgres userdb-postgrest + test/scripts/docker-logs $(NAMESPACE) userdb-postgres userdb-postgrest .PHONY: docker-build docker-build: diff --git a/cmd/client/api.go b/cmd/client/api.go index 2091f48..903a528 100644 --- a/cmd/client/api.go +++ b/cmd/client/api.go @@ -2,52 +2,56 @@ package main import ( "bytes" - "encoding/json" - "encoding/base64" "crypto/sha256" + "encoding/base64" + "encoding/json" "errors" "fmt" - "io/ioutil" + "io" "log" "math/rand" "net/http" "os" + "strings" "time" - "strings" ) type RequestBody struct { - Name string `json:"name"` - Host string `json:"host"` - Shell string `json:"shell"` - Keys []string `json:"keys"` + Name string `json:"name"` + Host string `json:"host"` + Shell string `json:"shell"` + Keys []string `json:"keys"` } type ResponseBody struct { - Hint string `json:"hint"` - Details string `json:"details"` - Message string `json:"message"` - Code string `json:"code"` - Request RequestBody `json:"request"` + Hint string `json:"hint"` + Details string `json:"details"` + Message string `json:"message"` + Code string `json:"code"` + Request RequestBody `json:"request"` } type SshPublicKey struct { - Fingerprint string `json:"fingerprint"` - Base64Fingerprint string `json:"base64_fingerprint"` - Type string `json:"type"` - Key string `json:"key"` - Comment string `json:"comment"` - Uid int `json:"uid"` + Fingerprint string `json:"fingerprint"` + Base64Fingerprint string `json:"base64_fingerprint"` + Type string `json:"type"` + Key string `json:"key"` + Comment string `json:"comment"` + Uid int `json:"uid"` } type User struct { - Uid int `json:"uid"` - Name string `json:"name"` - Host string `json:"host"` - Type string `json:"type"` - Key string `json:"key"` - Comment string `json:"comment"` - Shell string `json:"shell"` + Uid int `json:"uid"` + Name string `json:"name"` + Host string `json:"host"` + Type string `json:"type"` + Key string `json:"key"` + Comment string `json:"comment"` + Shell string `json:"shell"` +} + +func (u User) String() string { + return u.Name } type Host struct { @@ -70,7 +74,7 @@ func getHosts() ([]string, error) { if err != nil { return hosts, err } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) defer res.Body.Close() if err != nil { return hosts, err @@ -91,17 +95,17 @@ func getKeys( key string, ) ([]SshPublicKey, error) { var sshPublicKeys []SshPublicKey - keyStripped := strings.Fields(key)[1] - keyDecoded, err := base64.StdEncoding.DecodeString(keyStripped) + keyStripped := strings.Fields(key)[1] + keyDecoded, err := base64.StdEncoding.DecodeString(keyStripped) if err != nil { return sshPublicKeys, err } - fingerprint := sha256.Sum256(keyDecoded) + fingerprint := sha256.Sum256(keyDecoded) apiUrl := fmt.Sprintf( - "%s/ssh_public_key?fingerprint=ilike.%x", - os.Getenv("API_URL"), - fingerprint, - ) + "%s/ssh_public_key?fingerprint=ilike.%x", + os.Getenv("API_URL"), + fingerprint, + ) apiToken := os.Getenv("API_TOKEN") req, _ := http.NewRequest("GET", apiUrl, nil) req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", apiToken)) @@ -111,7 +115,7 @@ func getKeys( if err != nil { return sshPublicKeys, err } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) defer res.Body.Close() if err != nil { return sshPublicKeys, err @@ -119,8 +123,8 @@ func getKeys( err = json.Unmarshal([]byte(body), &sshPublicKeys) if err != nil { return sshPublicKeys, err - } - return sshPublicKeys, nil + } + return sshPublicKeys, nil } func getUsersById( @@ -128,10 +132,10 @@ func getUsersById( ) ([]User, error) { var users []User apiUrl := fmt.Sprintf( - "%s/passwd?uid=eq.%d", - os.Getenv("API_URL"), - uid, - ) + "%s/passwd?uid=eq.%d", + os.Getenv("API_URL"), + uid, + ) apiToken := os.Getenv("API_TOKEN") req, _ := http.NewRequest("GET", apiUrl, nil) req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", apiToken)) @@ -141,7 +145,7 @@ func getUsersById( if err != nil { return users, err } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) defer res.Body.Close() if err != nil { return users, err @@ -149,8 +153,8 @@ func getUsersById( err = json.Unmarshal([]byte(body), &users) if err != nil { return users, err - } - return users, nil + } + return users, nil } func createUser( @@ -181,7 +185,7 @@ func createUser( logger.Println("[client] ++", string(jsonData)) return nil } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) defer res.Body.Close() if err != nil { return err @@ -199,9 +203,9 @@ func createUser( func editUser( logger *log.Logger, - user User, - sshPublicKeys []SshPublicKey, + user User, + _ []SshPublicKey, ) error { - logger.Println("User: %s",user) + logger.Printf("User: %s", user) return errors.New("placeholder") } diff --git a/cmd/client/forms.go b/cmd/client/forms.go index f40d6f2..43bf2a1 100644 --- a/cmd/client/forms.go +++ b/cmd/client/forms.go @@ -96,8 +96,8 @@ func createForm( func editForm( logger *log.Logger, hosts []string, - user User, - sshPublicKeys []SshPublicKey, + user User, + sshPublicKeys []SshPublicKey, ) { app := tview.NewApplication() logo := tview.NewTextView() @@ -105,7 +105,7 @@ func editForm( logo.SetText(logoText) title := tview.NewTextView() title.SetTextAlign(1) - title.SetText(fmt.Sprintf("Editing User: \"%s\"",user.Name)) + title.SetText(fmt.Sprintf("Editing User: \"%s\"", user.Name)) frame := tview.NewFrame(func() tview.Primitive { form := tview.NewForm() form.SetLabelColor(tcell.ColorWhite) @@ -121,20 +121,20 @@ func editForm( form.AddInputField("Shell", user.Shell, 33, tview.InputFieldMaxLength(800), nil, ) - keyNum := len(sshPublicKeys) - for i:=0; i < len(sshPublicKeys); i++{ - key := sshPublicKeys[i] - keyString := fmt.Sprintf("%s %s",key.Type, key.Key) - form.AddInputField(fmt.Sprintf("Public Key %d",i+1), - keyString, 33, tview.InputFieldMaxLength(800), nil, - ) - } - form.AddButton("Add Key", func(){ - keyNum = keyNum + 1 - form.AddInputField(fmt.Sprintf("Public Key %d",keyNum), - "", 33, tview.InputFieldMaxLength(800), nil, - ) - }) + keyNum := len(sshPublicKeys) + for i := 0; i < len(sshPublicKeys); i++ { + key := sshPublicKeys[i] + keyString := fmt.Sprintf("%s %s", key.Type, key.Key) + form.AddInputField(fmt.Sprintf("Public Key %d", i+1), + keyString, 33, tview.InputFieldMaxLength(800), nil, + ) + } + form.AddButton("Add Key", func() { + keyNum = keyNum + 1 + form.AddInputField(fmt.Sprintf("Public Key %d", keyNum), + "", 33, tview.InputFieldMaxLength(800), nil, + ) + }) form.AddButton("Update", func() { //server_dropdown := form.GetFormItem(0).(*tview.DropDown) //_, server := server_dropdown.GetCurrentOption() @@ -147,8 +147,8 @@ func editForm( "\nError: Account update failed\n", fmt.Errorf("\n%v\n", err), ) - //TODO: update User and sshPublicKeys structs based on input - fmt.Fprintln(os.Stdout,"\nUser: ",user, sshPublicKeys) + //TODO: update User and sshPublicKeys structs based on input + fmt.Fprintln(os.Stdout, "\nUser: ", user, sshPublicKeys) os.Exit(1) } app.Stop() diff --git a/cmd/client/main.go b/cmd/client/main.go index 7d50fdd..e50fdb3 100644 --- a/cmd/client/main.go +++ b/cmd/client/main.go @@ -7,13 +7,12 @@ import ( ) func main() { - fd := os.NewFile(3, "/proc/self/fd/3") defer fd.Close() logger := log.New(fd, "", log.Ldate|log.Ltime) - key := os.Getenv("KEY") + key := os.Getenv("KEY") if key == "none" { - fmt.Fprintln( + fmt.Fprint( os.Stderr, "\nError: Public key authentication required\n", "\nFor help generating a key try:\n", @@ -21,26 +20,26 @@ func main() { ) os.Exit(1) } - keys, err := getKeys(key) + keys, err := getKeys(key) + if err != nil { + fmt.Fprintln(os.Stderr, "\nError: Unable to get keys list") + fmt.Fprintln(os.Stderr, err) + } + hosts, err := getHosts() if err != nil { - fmt.Fprintln(os.Stderr, "\nError: Unable to get keys list") - fmt.Fprintln(os.Stderr, err) - } - hosts, err := getHosts() - if err != nil { - fmt.Fprintln(os.Stderr, "\nError: Unable to get host list") - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } - if len(keys) == 0 { - createForm(logger, hosts) - } else { - users, err := getUsersById(keys[0].Uid) - if err != nil { - fmt.Fprintln(os.Stderr, "\nError: Unable to get user list") - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } - editForm(logger, hosts, users[0], keys) - } + fmt.Fprintln(os.Stderr, "\nError: Unable to get host list") + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + if len(keys) == 0 { + createForm(logger, hosts) + } else { + users, err := getUsersById(keys[0].Uid) + if err != nil { + fmt.Fprintln(os.Stderr, "\nError: Unable to get user list") + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + editForm(logger, hosts, users[0], keys) + } } diff --git a/cmd/server/main.go b/cmd/server/main.go index 881533c..ec64509 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -1,30 +1,34 @@ package main import ( - "encoding/json" - "crypto/sha512" + "crypto/ecdsa" "crypto/ed25519" + "crypto/elliptic" + "crypto/rsa" + "crypto/sha512" "encoding/binary" - "math/rand" + "encoding/json" "fmt" - "github.com/creack/pty" - "golang.org/x/crypto/ssh" - "golang.org/x/time/rate" "io" "log" + "math/rand" "net" "os" "os/exec" "path/filepath" + "regexp" "sync" "time" - "regexp" + + "github.com/creack/pty" + "golang.org/x/crypto/ssh" + "golang.org/x/time/rate" ) var limiter = NewIPRateLimiter(rate.Every(time.Minute), 10) var ( - hostPrivateKeySigner ssh.Signer + hostPrivateKeySigners []ssh.Signer ) type LoginData struct { @@ -39,6 +43,7 @@ func handleConnection(nConn net.Conn, sshConfig *ssh.ServerConfig) { addr, _ := conn.Conn.RemoteAddr().(*net.TCPAddr) ipAddress := addr.IP.String() sshKey := "none" + if conn.Permissions != nil { if conn.Permissions.Extensions != nil { if k, ok := conn.Permissions.Extensions["pubkey"]; ok { @@ -93,22 +98,22 @@ func handleConnection(nConn net.Conn, sshConfig *ssh.ServerConfig) { command := re.ReplaceAllString(string(req.Payload), "") log.Println("[server] <-", string(jsonLoginData)) switch command { - case "debug": - channel.Write([]byte(fmt.Sprintf( - "%s\n\r",jsonLoginData, - ))) - channel.SendRequest( - "exit-status", false, []byte{0, 0, 0, 0}, - ) - channel.Close() - return - default: - channel.Write([]byte(fmt.Sprintf( - "\n\rUnknown command: \"%s\"\n\n\r", - command, - ))) - channel.Close() - return + case "debug": + channel.Write([]byte(fmt.Sprintf( + "%s\n\r", jsonLoginData, + ))) + channel.SendRequest( + "exit-status", false, []byte{0, 0, 0, 0}, + ) + channel.Close() + return + default: + channel.Write([]byte(fmt.Sprintf( + "\n\rUnknown command: \"%s\"\n\n\r", + command, + ))) + channel.Close() + return } case "shell": runDir, _ := filepath.Abs(filepath.Dir(os.Args[0])) @@ -186,21 +191,100 @@ func init() { hash := sha512.New() io.WriteString(hash, os.Getenv("HOST_KEY_SEED")) var seed uint64 = binary.BigEndian.Uint64(hash.Sum(nil)[:8]) - var reader = NewSyncReader(rand.New(rand.NewSource(int64(seed)))) - pubKey, privKey, _ := ed25519.GenerateKey(reader) - sshPubKey, _ := ssh.NewPublicKey(pubKey) - hostPrivateKeySigner, _ = ssh.NewSignerFromKey(privKey) + + keys := make(map[string][]byte, 4) + + { + var sshKey ssh.PublicKey + var err error + var reader = NewSyncReader(rand.New(rand.NewSource(int64(seed)))) + + pubKey, privKey, err := ed25519.GenerateKey(reader) + if err != nil { + log.Println("ERROR: ", err) + } + + sshKey, err = ssh.NewPublicKey(pubKey) + if err != nil { + log.Println("ERROR: ", err) + } + + var signer ssh.Signer + signer, err = ssh.NewSignerFromKey(privKey) + if err != nil { + log.Println("ERROR: ", err) + } + + hostPrivateKeySigners = append(hostPrivateKeySigners, signer) + + keys["ed25519"] = ssh.MarshalAuthorizedKey(sshKey) + } + + { + var sshKey ssh.PublicKey + var err error + var reader = NewSyncReader(rand.New(rand.NewSource(int64(seed)))) + + privKey, err := rsa.GenerateKey(reader, 4096) + if err != nil { + log.Println("ERROR: ", err) + } + + sshKey, err = ssh.NewPublicKey(&privKey.PublicKey) + if err != nil { + log.Println("ERROR: ", err) + } + + var signer ssh.Signer + signer, err = ssh.NewSignerFromKey(privKey) + if err != nil { + log.Println("ERROR: ", err) + } + + hostPrivateKeySigners = append(hostPrivateKeySigners, signer) + + keys["rsa"] = ssh.MarshalAuthorizedKey(sshKey) + } + + { + var sshKey ssh.PublicKey + var err error + var reader = NewSyncReader(rand.New(rand.NewSource(int64(seed)))) + + privKey, err := ecdsa.GenerateKey(elliptic.P256(), reader) + if err != nil { + log.Println("ERROR: ", err) + } + + sshKey, err = ssh.NewPublicKey(&privKey.PublicKey) + if err != nil { + log.Println("ERROR: ", err) + } + + var signer ssh.Signer + signer, err = ssh.NewSignerFromKey(privKey) + if err != nil { + log.Println("ERROR: ", err) + } + + hostPrivateKeySigners = append(hostPrivateKeySigners, signer) + + keys["ecdsa"] = ssh.MarshalAuthorizedKey(sshKey) + } + fmt.Println("SSH Daemon Started") - fmt.Printf("Host Key: %s", ssh.MarshalAuthorizedKey(sshPubKey)) + fmt.Printf("Host Key: \n%s", keys) } func main() { - sshConfig := &ssh.ServerConfig{ KeyboardInteractiveCallback: keyboardInteractiveCallback, PublicKeyCallback: publicKeyCallback, } - sshConfig.AddHostKey(hostPrivateKeySigner) + + for _, signer := range hostPrivateKeySigners { + sshConfig.AddHostKey(signer) + } listener, err := net.Listen("tcp4", ":2222") if err != nil { @@ -209,10 +293,9 @@ func main() { for { conn, err := listener.Accept() if err != nil { - log.Println("!! %s", err) + log.Printf("!! %s", err) continue } go handleConnection(conn, sshConfig) } - } diff --git a/cmd/server/utils.go b/cmd/server/utils.go index 75bebfa..d50b42f 100644 --- a/cmd/server/utils.go +++ b/cmd/server/utils.go @@ -2,12 +2,13 @@ package main import ( "encoding/binary" - "golang.org/x/crypto/ssh" "os" "os/exec" "strings" "syscall" "unsafe" + + "golang.org/x/crypto/ssh" ) func setWinsize(fd uintptr, w, h uint32) { @@ -45,7 +46,8 @@ func publicKeyCallback( ) (*ssh.Permissions, error) { return &ssh.Permissions{ Extensions: map[string]string{ - "pubkey": strings.TrimSpace(string(ssh.MarshalAuthorizedKey(key))), + "pubkey": strings.TrimSpace(string(ssh.MarshalAuthorizedKey(key))), + "pubkey-fp": ssh.FingerprintSHA256(key), }, }, nil } diff --git a/go.mod b/go.mod index 7c973eb..f8f17f0 100644 --- a/go.mod +++ b/go.mod @@ -5,14 +5,16 @@ go 1.19 require ( github.com/creack/pty v1.1.7 github.com/gdamore/tcell v1.3.0 - github.com/kr/pty v1.1.8 github.com/rivo/tview v0.0.0-20191231100700-c6236f442139 - golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876 + golang.org/x/crypto v0.22.0 golang.org/x/time v0.0.0-20191024005414-555d28b269f0 +) + +require ( github.com/gdamore/encoding v1.0.0 // indirect github.com/lucasb-eyer/go-colorful v1.0.2 // indirect github.com/mattn/go-runewidth v0.0.4 // indirect github.com/rivo/uniseg v0.1.0 // indirect - golang.org/x/sys v0.0.0-20191018095205-727590c5006e // indirect - golang.org/x/text v0.3.2 // indirect + golang.org/x/sys v0.19.0 // indirect + golang.org/x/text v0.14.0 // indirect ) diff --git a/go.sum b/go.sum index 8f1bf49..c958dea 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +github.com/DATA-DOG/go-sqlmock v1.3.3 h1:CWUqKXe0s8A2z6qCgkP4Kru7wC11YoAnoupUKFDnH08= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/creack/pty v1.1.7 h1:6pwm8kMQKCmgUg0ZHTm5+/YvRK0s3THD/28+T6/kk4A= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= @@ -5,51 +6,25 @@ github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdk github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= github.com/gdamore/tcell v1.3.0 h1:r35w0JBADPZCVQijYebl6YMWWtHRqVEGt7kL2eBADRM= github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM= -github.com/gdamore/tcell v1.4.0 h1:vUnHwJRvcPQa3tzi+0QI4U9JINXYJlOz9yiaiPQ2wMU= -github.com/gdamore/tcell v1.4.0/go.mod h1:vxEiSDZdW3L+Uhjii9c3375IlDmR05bzxY404ZVSMo0= -github.com/gdamore/tcell/v2 v2.4.1-0.20210905002822-f057f0a857a1 h1:QqwPZCwh/k1uYqq6uXSb9TRDhTkfQbO80v8zhnIe5zM= -github.com/gdamore/tcell/v2 v2.4.1-0.20210905002822-f057f0a857a1/go.mod h1:Az6Jt+M5idSED2YPGtwnfJV0kXohgdCBPmHGSYc1r04= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/lucasb-eyer/go-colorful v1.0.2 h1:mCMFu6PgSozg9tDNMMK3g18oJBX7oYGrC09mS6CXfO4= github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s= -github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= -github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= -github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= -github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/rivo/tview v0.0.0-20191231100700-c6236f442139 h1:b47NuoXmK5Vg873mXlQdwtr0jNZd0zaaltm8sWoGscg= github.com/rivo/tview v0.0.0-20191231100700-c6236f442139/go.mod h1:/rBeY22VG2QprWnEqG57IBC8biVu3i0DOIjRLc9I8H0= -github.com/rivo/tview v0.0.0-20221128165837-db36428c92d9 h1:ccTgRxA37ypj3q8zB8G4k3xGPfBbIaMwrf3Yw6k50NY= -github.com/rivo/tview v0.0.0-20221128165837-db36428c92d9/go.mod h1:YX2wUZOcJGOIycErz2s9KvDaP0jnWwRCirQMPLPpQ+Y= github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8= -github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876 h1:sKJQZMuxjOAR/Uo2LBfU90onWEf1dF4C+0hPJCc9Mpc= -golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191018095205-727590c5006e h1:ZtoklVMHQy6BFRHkbG6JzK+S6rX82//Yeok1vMlizfQ= golang.org/x/sys v0.0.0-20191018095205-727590c5006e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 h1:46ULzRKLh1CwgRq2dC5SlBzEqqNCi8rreOZnNrbqcIY= -golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= -golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/test/Dockerfile b/test/Dockerfile index 9984096..38f6cf0 100644 --- a/test/Dockerfile +++ b/test/Dockerfile @@ -1,23 +1,27 @@ -FROM debian:buster +FROM debian:bookworm -RUN adduser admin && \ - apt-get clean && \ - apt-get update && \ - apt-get install -y --force-yes \ - bats \ - sudo \ - postgresql-client \ - curl \ - tmux \ - jq \ - ssh &&\ - rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* +RUN \ +<<-EOF + adduser admin + apt-get clean + apt-get update + apt-get install -y --force-yes \ + bats \ + bats-assert \ + sudo \ + postgresql-client \ + curl \ + tmux \ + jq \ + ssh + rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* +EOF WORKDIR /home/test -ENV LANG=C.UTF-8 \ - TZ=UTC \ - TERM=xterm-256color \ - HOME="/home/test" +ENV LANG=C.UTF-8 +ENV TZ=UTC +ENV TERM=xterm-256color +ENV HOME="/home/test" CMD ["/usr/bin/bats", "/test/test.bats"] diff --git a/test/keys/id_ecdsa b/test/keys/id_ecdsa new file mode 100644 index 0000000..8263d9d --- /dev/null +++ b/test/keys/id_ecdsa @@ -0,0 +1,8 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS +1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQSM+/gf8+cz56dMElmTfiZ0vIn2+FU9 +ju99nGgW4EFlbZMrXD4vWyw106DLzJjXb9FwfGIgV5HUAno+FX6LW29cAAAAoOEHU0DhB1 +NAAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBIz7+B/z5zPnp0wS +WZN+JnS8ifb4VT2O732caBbgQWVtkytcPi9bLDXToMvMmNdv0XB8YiBXkdQCej4Vfotbb1 +wAAAAgRuiy4336lmWXK4YFy9cvjd0RFuHRtBgawxzEuEtZE8MAAAAIcGpAZmV0Y2g= +-----END OPENSSH PRIVATE KEY----- diff --git a/test/keys/id_ecdsa.pub b/test/keys/id_ecdsa.pub new file mode 100644 index 0000000..2dbf47f --- /dev/null +++ b/test/keys/id_ecdsa.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBIz7+B/z5zPnp0wSWZN+JnS8ifb4VT2O732caBbgQWVtkytcPi9bLDXToMvMmNdv0XB8YiBXkdQCej4Vfotbb1w= pj@fetch diff --git a/test/test.bats b/test/test.bats index 702072d..10d5507 100644 --- a/test/test.bats +++ b/test/test.bats @@ -2,29 +2,55 @@ load test_helper @test "Cannot login without an ssh key" { run ssh_command - [ "$status" -eq 255 ] + + assert_failure } @test "can login with an ed25519 ssh key" { run ssh_command "ed25519" "jdoe" "debug" - [ "$status" -eq 0 ] - [[ "$output" == *"ssh-ed25519"* ]] + + assert_success + assert_output --partial "ssh-ed25519" } @test "can login with an rsa ssh key" { run ssh_command "rsa" "jdoe" "debug" - [ "$status" -eq 0 ] - [[ "$output" == *"rsa"* ]] + + assert_success + assert_output --partial "ssh-rsa" +} + +@test "can login with an ecdsa ssh key" { + run ssh_command "ecdsa" "jdoe" "debug" + + assert_success + assert_output --partial "ecdsa-sha2-nistp256" } @test "Cannot run an invalid command" { run ssh_command "ed25519" "jdoe" "invalid" - [ "$status" -eq 255 ] - [[ "$output" == *"Unknown command"* ]] + + assert_failure + assert_output --partial "Unknown command" } @test "Can create user with an ed25519 ssh key" { - run tmux_command "ssh_command ed25519" + run tmux_command "ssh_command ed25519 user-ed25519" run tmux_keys TAB TAB TAB ENTER - [ "$status" -eq 0 ] + + assert_success +} + +@test "Can create user with an rsa ssh key" { + run tmux_command "ssh_command rsa user-rsa" + run tmux_keys TAB TAB TAB ENTER + + assert_success +} + +@test "Can create user with an ecdsa ssh key" { + run tmux_command "ssh_command ecdsa user-ecdsa" + run tmux_keys TAB TAB TAB ENTER + + assert_success } diff --git a/test/test_helper.bash b/test/test_helper.bash index 2b6fbd7..611214a 100644 --- a/test/test_helper.bash +++ b/test/test_helper.bash @@ -1,6 +1,9 @@ #!/bin/bash setup(){ + bats_load_library bats-support + bats_load_library bats-assert + echo "Settting up test" psql -c "insert into hosts (name,maxusers) values ('test.hashbang.sh','500');"; psql -c "insert into hosts (name,maxusers) values ('test2.hashbang.sh','500');";