github.com/koron/hk@v0.0.0-20150303213137-b8aeaa3ab34c/keys.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "errors" 6 "io/ioutil" 7 "log" 8 "os" 9 "os/exec" 10 "path/filepath" 11 "syscall" 12 "text/tabwriter" 13 14 "github.com/heroku/hk/hkclient" 15 ) 16 17 var ( 18 sshPubKeyPath string 19 ) 20 21 var cmdKeys = &Command{ 22 Run: runKeys, 23 Usage: "keys", 24 Category: "account", 25 Short: "list ssh public keys" + extra, 26 Long: ` 27 Keys lists SSH public keys associated with your Heroku account. 28 29 Examples: 30 31 $ hk keys 32 5e:67:40:b6:79:db:56:47:cd:3a:a7:65:ab:ed:12:34 user@test.com 33 `, 34 } 35 36 func runKeys(cmd *Command, args []string) { 37 if len(args) != 0 { 38 cmd.PrintUsage() 39 os.Exit(2) 40 } 41 42 keys, err := client.KeyList(nil) 43 must(err) 44 45 w := tabwriter.NewWriter(os.Stdout, 1, 2, 2, ' ', 0) 46 defer w.Flush() 47 48 for i := range keys { 49 listRec(w, 50 keys[i].Fingerprint, 51 keys[i].Email, 52 ) 53 } 54 } 55 56 var cmdKeyAdd = &Command{ 57 Run: runKeyAdd, 58 Usage: "key-add [<public-key-file>]", 59 Category: "account", 60 Short: "add ssh public key" + extra, 61 Long: ` 62 Command key-add adds an ssh public key to your Heroku account. 63 64 It tries these sources for keys, in order: 65 66 1. public-key-file argument, if present 67 2. output of ssh-add -L, if any 68 3. file $HOME/.ssh/id_rsa.pub 69 `, 70 } 71 72 func runKeyAdd(cmd *Command, args []string) { 73 if len(args) > 1 { 74 cmd.PrintUsage() 75 os.Exit(2) 76 } 77 if len(args) == 1 { 78 sshPubKeyPath = args[0] 79 } 80 keys, err := findKeys() 81 if err != nil { 82 if _, ok := err.(privKeyError); ok { 83 log.Println("refusing to upload") 84 } 85 printFatal(err.Error()) 86 } 87 88 key, err := client.KeyCreate(string(keys)) 89 must(err) 90 log.Printf("Key %s for %s added.", abbrev(key.Fingerprint, 15), key.Email) 91 } 92 93 func findKeys() ([]byte, error) { 94 if sshPubKeyPath != "" { 95 return sshReadPubKey(sshPubKeyPath) 96 } 97 98 out, err := exec.Command("ssh-add", "-L").Output() 99 if err != nil { 100 return nil, err 101 } 102 if len(out) != 0 { 103 print(string(out)) 104 return out, nil 105 } 106 107 key, err := sshReadPubKey(filepath.Join(hkclient.HomePath(), ".ssh", "id_rsa.pub")) 108 switch err { 109 case syscall.ENOENT: 110 return nil, errors.New("No SSH keys found") 111 case nil: 112 return key, nil 113 } 114 return nil, err 115 } 116 117 func sshReadPubKey(s string) ([]byte, error) { 118 f, err := os.Open(filepath.FromSlash(s)) 119 if err != nil { 120 return nil, err 121 } 122 123 key, err := ioutil.ReadAll(f) 124 if err != nil { 125 return nil, err 126 } 127 128 if bytes.Contains(key, []byte("PRIVATE")) { 129 return nil, privKeyError(s) 130 } 131 132 return key, nil 133 } 134 135 type privKeyError string 136 137 func (e privKeyError) Error() string { 138 return "appears to be a private key: " + string(e) 139 } 140 141 var cmdKeyRemove = &Command{ 142 Run: runKeyRemove, 143 Usage: "key-remove <fingerprint>", 144 Category: "account", 145 Short: "remove an ssh public key" + extra, 146 Long: ` 147 Command key-remove removes an ssh public key from your Heroku account. 148 149 Examples: 150 151 $ hk key-remove 5e:67:40:b6:79:db:56:47:cd:3a:a7:65:ab:ed:12:34 152 Key 5e:67:40:b6:79:db… removed. 153 `, 154 } 155 156 func runKeyRemove(cmd *Command, args []string) { 157 if len(args) != 1 { 158 cmd.PrintUsage() 159 os.Exit(2) 160 } 161 fingerprint := args[0] 162 163 err := client.KeyDelete(fingerprint) 164 must(err) 165 log.Printf("Key %s removed.", abbrev(fingerprint, 18)) 166 }