package projects import ( "fmt" "net/http" "github.com/semaphoreui/semaphore/api/helpers" "github.com/semaphoreui/semaphore/db" "github.com/gorilla/context" ) // KeyMiddleware ensures a key exists and loads it to the context func KeyMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { project := context.Get(r, "project").(db.Project) keyID, err := helpers.GetIntParam("key_id", w, r) if err != nil { return } key, err := helpers.Store(r).GetAccessKey(project.ID, keyID) if err != nil { helpers.WriteError(w, err) return } context.Set(r, "accessKey", key) next.ServeHTTP(w, r) }) } func GetKeyRefs(w http.ResponseWriter, r *http.Request) { key := context.Get(r, "accessKey").(db.AccessKey) refs, err := helpers.Store(r).GetAccessKeyRefs(*key.ProjectID, key.ID) if err != nil { helpers.WriteError(w, err) return } helpers.WriteJSON(w, http.StatusOK, refs) } // GetKeys retrieves sorted keys from the database func GetKeys(w http.ResponseWriter, r *http.Request) { if key := context.Get(r, "accessKey"); key != nil { k := key.(db.AccessKey) helpers.WriteJSON(w, http.StatusOK, k) return } project := context.Get(r, "project").(db.Project) var keys []db.AccessKey keys, err := helpers.Store(r).GetAccessKeys(project.ID, helpers.QueryParams(r.URL)) if err != nil { helpers.WriteError(w, err) return } helpers.WriteJSON(w, http.StatusOK, keys) } // AddKey adds a new key to the database func AddKey(w http.ResponseWriter, r *http.Request) { project := context.Get(r, "project").(db.Project) var key db.AccessKey if !helpers.Bind(w, r, &key) { return } if key.ProjectID == nil || *key.ProjectID != project.ID { helpers.WriteJSON(w, http.StatusBadRequest, map[string]string{ "error": "Project ID in body and URL must be the same", }) return } if err := key.Validate(true); err != nil { helpers.WriteJSON(w, http.StatusBadRequest, map[string]string{ "error": err.Error(), }) return } newKey, err := helpers.Store(r).CreateAccessKey(key) if err != nil { helpers.WriteError(w, err) return } helpers.EventLog(r, helpers.EventLogCreate, helpers.EventLogItem{ UserID: helpers.UserFromContext(r).ID, ProjectID: *newKey.ProjectID, ObjectType: db.EventKey, ObjectID: newKey.ID, Description: fmt.Sprintf("Access Key %s created", key.Name), }) // Reload key to drop sensitive fields key, err = helpers.Store(r).GetAccessKey(*newKey.ProjectID, newKey.ID) if err != nil { helpers.WriteError(w, err) return } helpers.WriteJSON(w, http.StatusCreated, key) } // UpdateKey updates key in database // nolint: gocyclo func UpdateKey(w http.ResponseWriter, r *http.Request) { var key db.AccessKey oldKey := context.Get(r, "accessKey").(db.AccessKey) if !helpers.Bind(w, r, &key) { return } repos, err := helpers.Store(r).GetRepositories(*key.ProjectID, db.RetrieveQueryParams{}) if err != nil { helpers.WriteError(w, err) return } for _, repo := range repos { if repo.SSHKeyID != key.ID { continue } err = repo.ClearCache() if err != nil { helpers.WriteError(w, err) return } } err = helpers.Store(r).UpdateAccessKey(key) if err != nil { helpers.WriteError(w, err) return } helpers.EventLog(r, helpers.EventLogUpdate, helpers.EventLogItem{ UserID: helpers.UserFromContext(r).ID, ProjectID: *oldKey.ProjectID, ObjectType: db.EventKey, ObjectID: oldKey.ID, Description: fmt.Sprintf("Access Key %s updated", key.Name), }) w.WriteHeader(http.StatusNoContent) } // RemoveKey deletes a key from the database func RemoveKey(w http.ResponseWriter, r *http.Request) { key := context.Get(r, "accessKey").(db.AccessKey) err := helpers.Store(r).DeleteAccessKey(*key.ProjectID, key.ID) if err == db.ErrInvalidOperation { helpers.WriteJSON(w, http.StatusBadRequest, map[string]interface{}{ "error": "Access Key is in use by one or more templates", "inUse": true, }) return } if err != nil { helpers.WriteError(w, err) return } helpers.EventLog(r, helpers.EventLogDelete, helpers.EventLogItem{ UserID: helpers.UserFromContext(r).ID, ProjectID: *key.ProjectID, ObjectType: db.EventKey, ObjectID: key.ID, Description: fmt.Sprintf("Access Key %s deleted", key.Name), }) w.WriteHeader(http.StatusNoContent) }