package main import ( "encoding/json" "flag" "fmt" "io/ioutil" "log" "net/http" "os" "time" ) var NO_RESPONSE string = "" var listen *string = flag.String("listen", ":8000", "\"[address]:\" to bind to. [default: \":8000\"]") var username *string = flag.String("username", "", "GitHub username to fetch keys for. [required]") var ttl *int64 = flag.Int64("ttl", 86400, "Time in seconds to cache GitHub keys for. [default: 86400 (one day)]") var cache []string = make([]string, 0) var expire int64 = 0 func fetchKeys() error { fmt.Fprintf(os.Stderr, "Fetching keys for GitHub user \"%s\"\n", *username) var resp *http.Response var err error var uri string = fmt.Sprintf("https://api.github.com/users/%s/keys", *username) resp, err = http.Get(uri) if err != nil { return err } defer resp.Body.Close() var body []byte body, err = ioutil.ReadAll(resp.Body) if err != nil { return err } var keys []map[string]interface{} = make([]map[string]interface{}, 0) err = json.Unmarshal(body, &keys) if err != nil { return err } var newCache []string = make([]string, 0) for _, key := range keys { newCache = append(newCache, key["key"].(string)) } var newExpire int64 = time.Now().UTC().Unix() + *ttl cache = newCache expire = newExpire return nil } func getResponse(r *http.Request) (int, string) { if r.Method != "GET" { return http.StatusMethodNotAllowed, NO_RESPONSE } var err error var now int64 = time.Now().UTC().Unix() if now >= expire { err = fetchKeys() if err != nil { return http.StatusInternalServerError, NO_RESPONSE } } if len(cache) > 0 { var response string = "" for _, key := range cache { response += fmt.Sprintf("%s\n", key) } return http.StatusOK, response } return http.StatusNoContent, NO_RESPONSE } func handle(w http.ResponseWriter, r *http.Request) { var status int var response string status, response = getResponse(r) w.WriteHeader(status) fmt.Fprintf(w, response) fmt.Fprintf( os.Stdout, "\"%d\"\t\"%d\"\t\"%s\"\t\"%s\"\t\"%s\"\t\"%s\"\t\"%s\"\t\"%s\"\n", status, len(response), r.Method, r.URL, r.Proto, r.Host, r.RemoteAddr, r.UserAgent(), ) } func main() { flag.Parse() if *username == "" { log.Fatal("Must provide `-username` parameter. e.g. `github-keys -username \"github-username\"`") } var err error err = fetchKeys() if err != nil { log.Fatal(err) } fmt.Fprintf(os.Stderr, "Starting server on \"%s\" for GitHub user \"%s\"\n", *listen, *username) http.HandleFunc("/", handle) err = http.ListenAndServe(*listen, nil) if err != nil { log.Fatal(err) } }