| @ -1,19 +1,103 @@ | |||
| package main | |||
| import ( | |||
| "encoding/json" | |||
| "flag" | |||
| "fmt" | |||
| "io/ioutil" | |||
| "log" | |||
| "net/http" | |||
| "time" | |||
| ) | |||
| var cached []string = make([]string, 0) | |||
| var ttl int = 0 | |||
| var listen *string = flag.String("listen", ":8000", "\"[address]:<port>\" 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.Printf("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 logRequest(r *http.Request) { | |||
| fmt.Printf("\"%s\"\t\"%s\"\t\"%s\"\t\"%s\"\t\"%s\"\t\"%s\"", r.Method, r.URL, r.Proto, r.Host, r.RemoteAddr, r.RequestURI) | |||
| } | |||
| func handle(w http.ResponseWriter, r *http.Request) { | |||
| logRequest(r) | |||
| if r.Method != "GET" { | |||
| w.WriteHeader(http.StatusMethodNotAllowed) | |||
| return | |||
| } | |||
| var err error | |||
| var now int64 = time.Now().UTC().Unix() | |||
| if now >= expire { | |||
| err = fetchKeys() | |||
| if err != nil { | |||
| w.WriteHeader(http.StatusInternalServerError) | |||
| return | |||
| } | |||
| } | |||
| if len(cache) > 0 { | |||
| w.WriteHeader(http.StatusOK) | |||
| for _, key := range cache { | |||
| fmt.Fprintf(w, "%s\n", key) | |||
| } | |||
| } else { | |||
| w.WriteHeader(http.StatusNoContent) | |||
| } | |||
| } | |||
| 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.Printf("Starting server on \"%s\" for GitHub user \"%s\"\n", *listen, *username) | |||
| http.HandleFunc("/", handle) | |||
| log.Fatal(http.ListenAndServe(":8000", nil)) | |||
| err = http.ListenAndServe(*listen, nil) | |||
| if err != nil { | |||
| log.Fatal(err) | |||
| } | |||
| } | |||