cat / 012
clone

a spreadsheet for the terminal: lotus 1-2-3 looks, google sheets keys and formulas, one go binary

cat/module-path
012 / internal / serve / keys_test.go
keys_test.go 4.4K
1package serve23import (4 "os"5 "path/filepath"6 "strings"7 "testing"89 gossh "golang.org/x/crypto/ssh"10)1112func TestAuthorizedKeys(t *testing.T) {13 keys := []gossh.Signer{newKey(t), newKey(t), newKey(t), newKey(t), newKey(t), newKey(t)}14 line := func(i int, opts string) string {15 s := strings.TrimSpace(string(gossh.MarshalAuthorizedKey(keys[i].PublicKey())))16 if opts != "" {17 s = opts + " " + s18 }19 return s + " user@host\n"20 }21 content := "# comment\n\n" +22 line(0, "") +23 line(1, `command="rrsync /backup"`) + // a restricted backup key: not for 01224 line(2, `from="10.0.0.0/8"`) + // 012 can't check where it comes from25 line(3, "restrict") + // no terminal26 line(4, "restrict,pty") +27 line(5, "no-port-forwarding,no-agent-forwarding")28 path := filepath.Join(t.TempDir(), "authorized_keys")29 os.WriteFile(path, []byte(content), 0o600)30 got, skipped, err := authorizedKeys(path)31 if err != nil {32 t.Fatal(err)33 }34 want := []int{0, 4, 5}35 if len(got) != len(want) || skipped != 3 {36 t.Fatalf("got %d keys, skipped %d; want %d and 3", len(got), skipped, len(want))37 }38 for i, k := range want {39 if fingerprint(got[i]) != fingerprint(keys[k].PublicKey()) {40 t.Errorf("key %d is not key %d", i, k)41 }42 }4344 // Writable by others: refused, as sshd's StrictModes does.45 os.Chmod(path, 0o620)46 if _, _, err := authorizedKeys(path); err == nil || !strings.Contains(err.Error(), "written by others") {47 t.Errorf("group-writable file: %v", err)48 }49 os.Chmod(path, 0o644)50 if _, _, err := authorizedKeys(path); err != nil {51 t.Errorf("0644 file: %v", err)52 }5354 // A line that doesn't parse names its line.55 os.WriteFile(path, []byte(line(0, "")+"ssh-ed25519 notbase64!\n"), 0o600)56 if _, _, err := authorizedKeys(path); err == nil || !strings.Contains(err.Error(), ":2:") {57 t.Errorf("bad line: %v", err)58 }59 if _, _, err := authorizedKeys(filepath.Join(t.TempDir(), "missing")); err == nil {60 t.Error("missing file accepted")61 }62 if _, _, err := authorizedKeys(t.TempDir()); err == nil {63 t.Error("a directory accepted")64 }65}6667func TestHostKey(t *testing.T) {68 dir := filepath.Join(t.TempDir(), "config", "012")69 path := filepath.Join(dir, "ssh_host_ed25519_key")70 s1, err := hostKey(path)71 if err != nil {72 t.Fatal(err)73 }74 if s1.PublicKey().Type() != gossh.KeyAlgoED25519 {75 t.Errorf("host key type %s", s1.PublicKey().Type())76 }77 for p, want := range map[string]os.FileMode{path: 0o600, dir: 0o700 | os.ModeDir, path + ".pub": 0o644} {78 if st, err := os.Stat(p); err != nil || st.Mode() != want {79 t.Errorf("%s: mode %v, %v; want %v", filepath.Base(p), st.Mode(), err, want)80 }81 }82 // Loaded again, not regenerated.83 s2, err := hostKey(path)84 if err != nil || fingerprint(s2.PublicKey()) != fingerprint(s1.PublicKey()) {85 t.Errorf("reloaded host key differs: %v", err)86 }87 os.Chmod(path, 0o644)88 if _, err := hostKey(path); err == nil || !strings.Contains(err.Error(), "chmod 600") {89 t.Errorf("readable host key: %v", err)90 }91}9293func TestNewChecks(t *testing.T) {94 key := newKey(t)95 top := t.TempDir()96 ak := filepath.Join(top, "authorized_keys")97 os.WriteFile(ak, gossh.MarshalAuthorizedKey(key.PublicKey()), 0o600)98 empty := filepath.Join(top, "empty")99 os.WriteFile(empty, []byte("# nobody\n"), 0o600)100 base := Options{Dir: top, Listen: "127.0.0.1:0", AuthorizedKeys: ak, HostKey: filepath.Join(top, "hk"), MaxSessions: 1}101 cases := map[string]func(*Options){102 "missing dir": func(o *Options) { o.Dir = filepath.Join(top, "nope") },103 "no keys": func(o *Options) { o.AuthorizedKeys = empty },104 "missing keys": func(o *Options) { o.AuthorizedKeys = filepath.Join(top, "nope") },105 "no listen": func(o *Options) { o.Listen = "" },106 "no sessions": func(o *Options) { o.MaxSessions = 0 },107 "negative idle": func(o *Options) { o.IdleTimeout = -1 },108 "no host key": func(o *Options) { o.HostKey = "" },109 "no authorized keys": func(o *Options) { o.AuthorizedKeys = "" },110 }111 for name, change := range cases {112 o := base113 change(&o)114 if _, err := New(o, Deps{}); err == nil {115 t.Errorf("%s: New succeeded", name)116 }117 }118 if _, err := New(base, Deps{}); err != nil {119 t.Errorf("valid options: %v", err)120 }121 d := Defaults()122 if d.Listen != "127.0.0.1:2312" || !strings.HasSuffix(d.AuthorizedKeys, filepath.Join(".ssh", "authorized_keys")) ||123 !strings.HasSuffix(d.HostKey, filepath.Join("012", "ssh_host_ed25519_key")) || d.IdleTimeout <= 0 || d.MaxSessions <= 0 {124 t.Errorf("Defaults() = %+v", d)125 }126}