package controller import ( "bytes" "fmt" "io/ioutil" "net/http" "github.com/gin-gonic/gin" "gopkg.in/yaml.v2" "github.com/drone/drone/model" "github.com/drone/drone/router/middleware/context" "github.com/drone/drone/router/middleware/session" "github.com/drone/drone/shared/crypto" "github.com/drone/drone/shared/httputil" "github.com/drone/drone/shared/token" ) func PostRepo(c *gin.Context) { db := context.Database(c) remote := context.Remote(c) user := session.User(c) owner := c.Param("owner") name := c.Param("name") if user == nil { c.AbortWithStatus(403) return } r, err := remote.Repo(user, owner, name) if err != nil { c.String(404, err.Error()) return } m, err := remote.Perm(user, owner, name) if err != nil { c.String(404, err.Error()) return } if !m.Admin { c.String(403, "Administrative access is required.") return } // error if the repository already exists _, err = model.GetRepoName(db, owner, name) if err == nil { c.String(409, "Repository already exists.") return } // set the repository owner to the // currently authenticated user. r.UserID = user.ID r.AllowPush = true r.AllowPull = true r.Timeout = 60 // 1 hour default build time r.Hash = crypto.Rand() // crates the jwt token used to verify the repository t := token.New(token.HookToken, r.FullName) sig, err := t.Sign(r.Hash) if err != nil { c.AbortWithError(500, err) return } link := fmt.Sprintf( "%s/hook?access_token=%s", httputil.GetURL(c.Request), sig, ) // generate an RSA key and add to the repo key, err := crypto.GeneratePrivateKey() if err != nil { c.AbortWithError(500, err) return } keys := new(model.Key) keys.Public = string(crypto.MarshalPublicKey(&key.PublicKey)) keys.Private = string(crypto.MarshalPrivateKey(key)) // activate the repository before we make any // local changes to the database. err = remote.Activate(user, r, keys, link) if err != nil { c.AbortWithError(500, err) return } tx, err := db.Begin() if err != nil { c.AbortWithError(500, err) return } defer tx.Rollback() // persist the repository err = model.CreateRepo(tx, r) if err != nil { c.AbortWithError(500, err) return } keys.RepoID = r.ID err = model.CreateKey(tx, keys) if err != nil { c.AbortWithError(500, err) return } err = model.CreateStar(tx, user, r) if err != nil { c.AbortWithError(500, err) return } tx.Commit() c.JSON(200, r) } func PatchRepo(c *gin.Context) { db := context.Database(c) repo := session.Repo(c) user := session.User(c) in := &struct { IsTrusted *bool `json:"trusted,omitempty"` Timeout *int64 `json:"timeout,omitempty"` AllowPull *bool `json:"allow_pr,omitempty"` AllowPush *bool `json:"allow_push,omitempty"` AllowDeploy *bool `json:"allow_deploy,omitempty"` AllowTag *bool `json:"allow_tag,omitempty"` }{} if err := c.Bind(in); err != nil { c.AbortWithError(http.StatusBadRequest, err) return } if in.AllowPush != nil { repo.AllowPush = *in.AllowPush } if in.AllowPull != nil { repo.AllowPull = *in.AllowPull } if in.AllowDeploy != nil { repo.AllowDeploy = *in.AllowDeploy } if in.AllowTag != nil { repo.AllowTag = *in.AllowTag } if in.IsTrusted != nil && user.Admin { repo.IsTrusted = *in.IsTrusted } if in.Timeout != nil && user.Admin { repo.Timeout = *in.Timeout } err := model.UpdateRepo(db, repo) if err != nil { c.AbortWithError(http.StatusInternalServerError, err) return } // if the user is authenticated we should // check to see if they've starred the repository repo.IsStarred, _ = model.GetStar(db, user, repo) c.IndentedJSON(http.StatusOK, repo) } func GetRepo(c *gin.Context) { db := context.Database(c) repo := session.Repo(c) user := session.User(c) if user == nil { c.IndentedJSON(http.StatusOK, repo) return } // if the user is authenticated we should // check to see if they've starred the repository repo.IsStarred, _ = model.GetStar(db, user, repo) c.IndentedJSON(http.StatusOK, repo) } func GetRepoKey(c *gin.Context) { db := context.Database(c) repo := session.Repo(c) keys, err := model.GetKey(db, repo) if err != nil { c.AbortWithError(http.StatusNotFound, err) } else { c.String(http.StatusOK, keys.Public) } } func DeleteRepo(c *gin.Context) { db := context.Database(c) remote := context.Remote(c) repo := session.Repo(c) user := session.User(c) err := model.DeleteRepo(db, repo) if err != nil { c.AbortWithError(http.StatusInternalServerError, err) return } remote.Deactivate(user, repo, httputil.GetURL(c.Request)) c.Writer.WriteHeader(http.StatusOK) } func PostSecure(c *gin.Context) { db := context.Database(c) repo := session.Repo(c) in, err := ioutil.ReadAll(c.Request.Body) if err != nil { c.AbortWithError(http.StatusBadRequest, err) return } // we found some strange characters included in // the yaml file when entered into a browser textarea. // these need to be removed in = bytes.Replace(in, []byte{'\xA0'}, []byte{' '}, -1) // make sure the Yaml is valid format to prevent // a malformed value from being used in the build err = yaml.Unmarshal(in, &yaml.MapSlice{}) if err != nil { c.String(http.StatusBadRequest, err.Error()) return } key, err := model.GetKey(db, repo) if err != nil { c.AbortWithError(http.StatusInternalServerError, err) return } // encrypts using go-jose out, err := crypto.Encrypt(string(in), key.Private) if err != nil { c.AbortWithError(http.StatusInternalServerError, err) return } c.String(http.StatusOK, out) } func PostStar(c *gin.Context) { db := context.Database(c) repo := session.Repo(c) user := session.User(c) err := model.CreateStar(db, user, repo) if err != nil { c.AbortWithError(http.StatusInternalServerError, err) } else { c.Writer.WriteHeader(http.StatusOK) } } func DeleteStar(c *gin.Context) { db := context.Database(c) repo := session.Repo(c) user := session.User(c) err := model.DeleteStar(db, user, repo) if err != nil { c.AbortWithError(http.StatusInternalServerError, err) } else { c.Writer.WriteHeader(http.StatusOK) } }