github.com/drycc/workflow-cli@v1.5.3-0.20240322092846-d4ee25983af9/cmd/keys.go (about) 1 package cmd 2 3 import ( 4 "fmt" 5 "io" 6 "os" 7 "path/filepath" 8 "strconv" 9 "strings" 10 11 "github.com/drycc/controller-sdk-go/api" 12 "github.com/drycc/controller-sdk-go/keys" 13 "github.com/drycc/workflow-cli/pkg/ssh" 14 "github.com/drycc/workflow-cli/settings" 15 ) 16 17 // KeysList lists a user's keys. 18 func (d *DryccCmd) KeysList(results int) error { 19 s, err := settings.Load(d.ConfigFile) 20 21 if err != nil { 22 return err 23 } 24 25 if results == defaultLimit { 26 results = s.Limit 27 } 28 29 keys, _, err := keys.List(s.Client, results) 30 if d.checkAPICompatibility(s.Client, err) != nil { 31 return err 32 } 33 34 if len(keys) > 0 { 35 table := d.getDefaultFormatTable([]string{"ID", "OWNER", "KEY"}) 36 for _, key := range keys { 37 table.Append([]string{ 38 key.ID, 39 key.Owner, 40 fmt.Sprintf("%s...%s", key.Public[:16], key.Public[len(key.Public)-10:]), 41 }) 42 } 43 table.Render() 44 } else { 45 d.Println("No any key found.") 46 } 47 return nil 48 } 49 50 // KeyRemove removes keys. 51 func (d *DryccCmd) KeyRemove(keyID string) error { 52 s, err := settings.Load(d.ConfigFile) 53 54 if err != nil { 55 return err 56 } 57 58 d.Printf("Removing %s SSH Key...", keyID) 59 60 if err = keys.Delete(s.Client, keyID); d.checkAPICompatibility(s.Client, err) != nil { 61 d.Println() 62 return err 63 } 64 65 d.Println(" done") 66 return nil 67 } 68 69 // KeyAdd adds keys. 70 func (d *DryccCmd) KeyAdd(name string, keyLocation string) error { 71 s, err := settings.Load(d.ConfigFile) 72 73 if err != nil { 74 return err 75 } 76 77 var key api.KeyCreateRequest 78 79 // check if name is the key 80 if name != "" && keyLocation == "" { 81 // detect of name is a file 82 _, err := os.Stat(name) 83 if err == nil { 84 keyLocation = name 85 name = "" 86 } 87 } 88 89 if keyLocation == "" { 90 ks, err := listKeys(d.WOut) 91 if err != nil { 92 return err 93 } 94 key, err = chooseKey(ks, d.WIn, d.WOut) 95 if err != nil { 96 return err 97 } 98 } else { 99 key, err = getKey(keyLocation) 100 if err != nil { 101 return err 102 } 103 } 104 105 // if name is provided by user then overwrite that in the key object 106 if name != "" { 107 key.ID = name 108 } 109 110 d.Printf("Uploading %s to drycc...", filepath.Base(key.Name)) 111 112 if _, err = keys.New(s.Client, key.ID, key.Public); d.checkAPICompatibility(s.Client, err) != nil { 113 d.Println() 114 return err 115 } 116 117 d.Println(" done") 118 return nil 119 } 120 121 func chooseKey(keys []api.KeyCreateRequest, input io.Reader, 122 wOut io.Writer) (api.KeyCreateRequest, error) { 123 fmt.Fprintln(wOut, "Found the following SSH public keys:") 124 125 for i, key := range keys { 126 fmt.Fprintf(wOut, "%d) %s %s\n", i+1, filepath.Base(key.Name), key.ID) 127 } 128 129 fmt.Fprintln(wOut, "0) Enter path to pubfile (or use keys:add <key_path>)") 130 131 var selected string 132 133 fmt.Fprint(wOut, "Which would you like to use with Drycc? ") 134 fmt.Fscanln(input, &selected) 135 136 numSelected, err := strconv.Atoi(selected) 137 138 if err != nil { 139 return api.KeyCreateRequest{}, fmt.Errorf("%s is not a valid integer", selected) 140 } 141 142 if numSelected < 0 || numSelected > len(keys) { 143 return api.KeyCreateRequest{}, fmt.Errorf("%d is not a valid option", numSelected) 144 } 145 146 if numSelected == 0 { 147 var filename string 148 149 fmt.Fprint(wOut, "Enter the path to the pubkey file: ") 150 fmt.Fscanln(input, &filename) 151 152 return getKey(filename) 153 } 154 155 return keys[numSelected-1], nil 156 } 157 158 func listKeys(wOut io.Writer) ([]api.KeyCreateRequest, error) { 159 folder := filepath.Join(settings.FindHome(), ".ssh") 160 files, err := os.ReadDir(folder) 161 162 if err != nil { 163 return nil, err 164 } 165 166 var keys []api.KeyCreateRequest 167 168 for _, file := range files { 169 if filepath.Ext(file.Name()) == ".pub" { 170 key, err := getKey(filepath.Join(folder, file.Name())) 171 172 if err == nil { 173 keys = append(keys, key) 174 } else { 175 fmt.Fprintln(wOut, err) 176 } 177 } 178 } 179 180 return keys, nil 181 } 182 183 func getKey(filename string) (api.KeyCreateRequest, error) { 184 keyContents, err := os.ReadFile(filename) 185 186 if err != nil { 187 return api.KeyCreateRequest{}, err 188 } 189 190 backupID := strings.Split(filepath.Base(filename), ".")[0] 191 keyInfo, err := ssh.ParsePubKey(backupID, keyContents) 192 if err != nil { 193 return api.KeyCreateRequest{}, fmt.Errorf("%s is not a valid ssh key", filename) 194 } 195 return api.KeyCreateRequest{ID: keyInfo.ID, Public: keyInfo.Public, Name: filename}, nil 196 }