aboutsummaryrefslogtreecommitdiff
path: root/main.go
blob: 69308b5bba0482c886af330576040d4e0ff2a68f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path"
	"strings"
	"time"
)

func main() {
	if len(os.Args) != 2 {
		fmt.Fprintln(os.Stderr, "no home directory provided")
		os.Exit(1)
	}
	homedir := os.Args[1]
	users, err := getUsers(homedir)
	if err != nil {
		if os.IsNotExist(err) {
			os.Exit(0)
		} else {
			fmt.Fprintf(os.Stderr, "could not read authorized_github_users: %v\n", err)
			os.Exit(1)
		}
	}
	keys, err := getUserKeys(users)
	if err != nil {
		fmt.Fprintf(os.Stderr, "could not get public keys: %v\n", err)
		os.Exit(1)
	}
	for _, key := range keys {
		fmt.Println(key)
	}
	os.Exit(0)
}

func getUsers(homedir string) ([]string, error) {
	filepath := path.Join(homedir, ".ssh", "authorized_github_users")
	data, err := ioutil.ReadFile(filepath)
	if err != nil {
		return nil, err
	}
	lines := strings.Split(string(data), "\n")
	users := map[string]struct{}{}
	for _, line := range lines {
		trimmed := strings.TrimSpace(line)
		if len(trimmed) > 0 && !strings.HasPrefix(trimmed, "#") {
			users[trimmed] = struct{}{}
		}
	}
	uniqueUsers := []string{}
	for user := range users {
		uniqueUsers = append(uniqueUsers, user)
	}
	return uniqueUsers, nil
}

// GHKey is a key structure from the GitHub REST API
type GHKey struct {
	ID  int    `json:"id"`
	Key string `json:"key"`
}

func getUserKeys(users []string) ([]string, error) {
	client := &http.Client{Timeout: 5 * time.Second}
	keys := []string{}
	for _, user := range users {
		url := fmt.Sprintf("https://api.github.com/users/%s/keys", user)
		res, err := client.Get(url)
		if err != nil {
			return nil, err
		}
		if res.StatusCode != http.StatusOK {
			return nil, fmt.Errorf("error fetching keys: got http %d %s", res.StatusCode, res.Status)
		}
		data, err := ioutil.ReadAll(res.Body)
		defer res.Body.Close()
		if err != nil {
			return nil, err
		}
		userKeys := []GHKey{}
		if err := json.Unmarshal(data, &userKeys); err != nil {
			return nil, err
		}
		for _, userKey := range userKeys {
			keys = append(keys, userKey.Key)
		}
	}
	return keys, nil
}