package main import ( "encoding/json" "errors" "net/http" "strings" "time" "github.com/gofrs/uuid" "github.com/gorilla/mux" "github.com/sirupsen/logrus" ) type apiServer struct { store storage } type apiResponse struct { Success bool `json:"success"` Error string `json:"error,omitempty"` Secret string `json:"secret,omitempty"` SecretId string `json:"secret_id,omitempty"` } type apiRequest struct { Secret string `json:"secret"` } func newAPI(s storage) *apiServer { return &apiServer{ store: s, } } func (a apiServer) Register(r *mux.Router) { r.HandleFunc("/create", a.handleCreate) r.HandleFunc("/get/{id}", a.handleRead) r.HandleFunc("/isWritable", func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusNoContent) }) } func (a apiServer) handleCreate(res http.ResponseWriter, r *http.Request) { var secret string if strings.HasPrefix(r.Header.Get("Content-Type"), "application/json") { tmp := apiRequest{} if err := json.NewDecoder(r.Body).Decode(&tmp); err != nil { a.errorResponse(res, http.StatusBadRequest, err, "decoding request body") return } secret = tmp.Secret } else { secret = r.FormValue("secret") } if secret == "" { a.errorResponse(res, http.StatusBadRequest, errors.New("secret missing"), "") return } id, err := a.store.Create(secret, time.Duration(cfg.SecretExpiry)*time.Second) if err != nil { a.errorResponse(res, http.StatusInternalServerError, err, "creating secret") return } a.jsonResponse(res, http.StatusCreated, apiResponse{ Success: true, SecretId: id, }) } func (a apiServer) handleRead(res http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) id := vars["id"] if id == "" { a.errorResponse(res, http.StatusBadRequest, errors.New("id missing"), "") return } secret, err := a.store.ReadAndDestroy(id) if err != nil { status := http.StatusInternalServerError if err == errSecretNotFound { status = http.StatusNotFound } a.errorResponse(res, status, err, "reading & destroying secret") return } a.jsonResponse(res, http.StatusOK, apiResponse{ Success: true, Secret: secret, }) } func (a apiServer) errorResponse(res http.ResponseWriter, status int, err error, desc string) { errID := uuid.Must(uuid.NewV4()).String() if desc != "" { // No description: Nothing interesting for the server log logrus.WithField("err_id", errID).WithError(err).Error(desc) } a.jsonResponse(res, status, apiResponse{ Error: errID, }) } func (a apiServer) jsonResponse(res http.ResponseWriter, status int, response apiResponse) { res.Header().Set("Content-Type", "application/json") res.Header().Set("Cache-Control", "no-store, max-age=0") res.WriteHeader(status) json.NewEncoder(res).Encode(response) }