Skip to content

Commit

Permalink
feat: add command to upload ssh keys
Browse files Browse the repository at this point in the history
  • Loading branch information
jonathongardner committed Sep 29, 2024
1 parent 9ea69ee commit 89504a2
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 14 deletions.
54 changes: 54 additions & 0 deletions setup/cli/github-push.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package cli

import (
"fmt"
"os"
"path/filepath"

"github.com/jonathongardner/linuxhelp/setup/github"
log "github.com/sirupsen/logrus"

"github.com/urfave/cli/v2"
)

var githubSSHPushCommand = &cli.Command{
Name: "push",
Usage: "Github push public ssh keys for user",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "path",
Aliases: []string{"p"},
Usage: "Path to public key",
DefaultText: "~/.ssh/id_rsa.pub",
},
&cli.StringFlag{
Name: "title",
Usage: "A description name for the key",
},
},
Action: func(c *cli.Context) error {
path := c.String("path")
if path == "" {
homedir, err := os.UserHomeDir()
if err != nil {
return fmt.Errorf("error getting home dir (%v)", err)
}
path = filepath.Join(homedir, ".ssh/id_rsa.pub")
}

githubApi := github.NewApi(c.String("host"), c.String("user"), c.String("token"))

key, err := os.ReadFile(path)
if err != nil {
return fmt.Errorf("error opening file %v (%v)", path, err)
}

fingerprint, err := githubApi.SSHSave(string(key), c.String("title"))
if err != nil {
return fmt.Errorf("error adding %v (%v)", fingerprint, err)
}
log.Infof("Added %v ssh", fingerprint)

return nil
},
}
9 changes: 5 additions & 4 deletions setup/cli/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ var githubSSHCommand = &cli.Command{
Usage: "Github ssh stuff",
Subcommands: []*cli.Command{
githubSSHPullCommand,
githubSSHPushCommand,
},
}

Expand All @@ -27,12 +28,12 @@ var githubCommand = &cli.Command{
Aliases: []string{"u"},
Required: true,
Usage: "User to pull ssh for",
EnvVars: []string{"GH_USER"},
},
&cli.StringFlag{
Name: "token",
Required: true,
Usage: "Authentication token",
EnvVars: []string{"GH_TOKEN"},
Name: "token",
Usage: "Authentication token",
EnvVars: []string{"GH_TOKEN"},
},
},
Subcommands: []*cli.Command{
Expand Down
40 changes: 39 additions & 1 deletion setup/github/api.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package github

import (
"bytes"
"encoding/json"
"fmt"
"io"
Expand Down Expand Up @@ -34,7 +35,7 @@ func (a API) get(path string, model any) error {

req.Header.Set("Accept", "application/vnd.github.v3+json")
if a.token != "" {
return fmt.Errorf("NOT SETUP")
req.Header.Set("Authorization", "Bearer "+a.token)
}

client := &http.Client{}
Expand All @@ -59,3 +60,40 @@ func (a API) get(path string, model any) error {

return nil
}

func (a API) post(path string, body []byte) error {
uri, err := url.JoinPath("https://", a.host, path)
if err != nil {
return fmt.Errorf("erroring creating url (%v)", err)
}
log.Debugf("POST: %v %v", uri, a.username)

req, err := http.NewRequest("POST", uri, bytes.NewBuffer(body))
if err != nil {
return fmt.Errorf("erroring creating request (%v)", err)
}

req.Header.Set("Accept", "application/vnd.github.v3+json")
req.Header.Set("X-GitHub-Api-Version", "2022-11-28")
if a.token != "" {
req.Header.Set("Authorization", "Bearer "+a.token)
}

client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("error making api request (%v)", err)
}

if resp.StatusCode < 299 {
return nil
}

resBody, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("error reading body (%v)", err)
}
log.Debugf("error: %v", string(resBody))

return fmt.Errorf("bad api response (%v)", resp.StatusCode)
}
36 changes: 28 additions & 8 deletions setup/github/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package github
import (
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"path"
"strconv"
Expand All @@ -27,20 +28,22 @@ func (k key) String() string {
return fmt.Sprintf("# sha256:%v imported from github\n%v %v-%v@%v", k.Fingerprint, k.Key, k.api.username, k.ID, k.api.host)
}

func (k *key) parse() error {
code := strings.Split(k.Key, " ")
func (k *key) parse() (err error) {
k.Fingerprint, err = fingerprint(k.Key)
return
}

func fingerprint(key string) (string, error) {
code := strings.Split(key, " ")
if len(code) <= 1 {
return fmt.Errorf("error splinting key")
return "", fmt.Errorf("error splinting key")
}
data, err := base64.StdEncoding.DecodeString(code[1])
if err != nil {
return fmt.Errorf("error base64 decoding %v", err)
return "", fmt.Errorf("error base64 decoding %v", err)
}
shaBits := sha256.Sum256(data)
k.Fingerprint = base64.StdEncoding.EncodeToString(shaBits[:])

// Digest::SHA256.base64digest(Base64.decode64(key['key'].split(' ')[1]))
return nil
return base64.StdEncoding.EncodeToString(shaBits[:]), nil
}

func (a API) SSHKeys() ([]*key, error) {
Expand All @@ -54,3 +57,20 @@ func (a API) SSHKeys() ([]*key, error) {
}
return toReturn, err
}

func (a API) SSHSave(key string, title string) (string, error) {
fp, err := fingerprint(key)
if err != nil {
return fp, err
}

toSend := map[string]string{"key": key}
if title != "" {
toSend["title"] = title
}
body, err := json.Marshal(toSend)
if err != nil {
return fp, fmt.Errorf("error marshaling body (%v)", err)
}
return fp, a.post(path.Join("user", "keys"), body)
}
2 changes: 1 addition & 1 deletion setup/version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v0.0.1
v0.1.0

0 comments on commit 89504a2

Please sign in to comment.