Exemple #1
0
func TeamsRepoAction(ctx *middleware.Context) {
	if !ctx.Org.IsOwner {
		ctx.Error(404)
		return
	}

	var err error
	switch ctx.Params(":action") {
	case "add":
		repoName := path.Base(ctx.Query("repo-name"))
		var repo *models.Repository
		repo, err = models.GetRepositoryByName(ctx.Org.Organization.Id, repoName)
		if err != nil {
			if models.IsErrRepoNotExist(err) {
				ctx.Flash.Error(ctx.Tr("org.teams.add_nonexistent_repo"))
				ctx.Redirect(ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName + "/repositories")
				return
			}
			ctx.Handle(500, "GetRepositoryByName", err)
			return
		}
		err = ctx.Org.Team.AddRepository(repo)
	case "remove":
		err = ctx.Org.Team.RemoveRepository(com.StrTo(ctx.Query("repoid")).MustInt64())
	}

	if err != nil {
		log.Error(3, "Action(%s): '%s' %v", ctx.Params(":action"), ctx.Org.Team.Name, err)
		ctx.Handle(500, "TeamsRepoAction", err)
		return
	}
	ctx.Redirect(ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName + "/repositories")
}
Exemple #2
0
func repoAssignment() macaron.Handler {
	return func(ctx *context.APIContext) {
		userName := ctx.Params(":username")
		repoName := ctx.Params(":reponame")

		var (
			owner *models.User
			err   error
		)

		// Check if the user is the same as the repository owner.
		if ctx.IsSigned && ctx.User.LowerName == strings.ToLower(userName) {
			owner = ctx.User
		} else {
			owner, err = models.GetUserByName(userName)
			if err != nil {
				if models.IsErrUserNotExist(err) {
					ctx.Status(404)
				} else {
					ctx.Error(500, "GetUserByName", err)
				}
				return
			}
		}
		ctx.Repo.Owner = owner

		// Get repository.
		repo, err := models.GetRepositoryByName(owner.ID, repoName)
		if err != nil {
			if models.IsErrRepoNotExist(err) {
				ctx.Status(404)
			} else {
				ctx.Error(500, "GetRepositoryByName", err)
			}
			return
		} else if err = repo.GetOwner(); err != nil {
			ctx.Error(500, "GetOwner", err)
			return
		}

		if ctx.IsSigned && ctx.User.IsAdmin {
			ctx.Repo.AccessMode = models.ACCESS_MODE_OWNER
		} else {
			mode, err := models.AccessLevel(ctx.User, repo)
			if err != nil {
				ctx.Error(500, "AccessLevel", err)
				return
			}
			ctx.Repo.AccessMode = mode
		}

		if !ctx.Repo.HasAccess() {
			ctx.Status(404)
			return
		}

		ctx.Repo.Repository = repo
	}
}
Exemple #3
0
func ApiRepoAssignment() macaron.Handler {
	return func(ctx *Context) {
		userName := ctx.Params(":username")
		repoName := ctx.Params(":reponame")

		var (
			u   *models.User
			err error
		)

		// Check if the user is the same as the repository owner.
		if ctx.IsSigned && ctx.User.LowerName == strings.ToLower(userName) {
			u = ctx.User
		} else {
			u, err = models.GetUserByName(userName)
			if err != nil {
				if err == models.ErrUserNotExist {
					ctx.Error(404)
				} else {
					ctx.JSON(500, &base.ApiJsonErr{"GetUserByName: " + err.Error(), base.DOC_URL})
				}
				return
			}
		}
		ctx.Repo.Owner = u

		// Get repository.
		repo, err := models.GetRepositoryByName(u.Id, repoName)
		if err != nil {
			if models.IsErrRepoNotExist(err) {
				ctx.Error(404)
			} else {
				ctx.JSON(500, &base.ApiJsonErr{"GetRepositoryByName: " + err.Error(), base.DOC_URL})
			}
			return
		} else if err = repo.GetOwner(); err != nil {
			ctx.JSON(500, &base.ApiJsonErr{"GetOwner: " + err.Error(), base.DOC_URL})
			return
		}

		mode, err := models.AccessLevel(ctx.User, repo)
		if err != nil {
			ctx.JSON(500, &base.ApiJsonErr{"AccessLevel: " + err.Error(), base.DOC_URL})
			return
		}

		ctx.Repo.AccessMode = mode

		// Check access.
		if ctx.Repo.AccessMode == models.ACCESS_MODE_NONE {
			ctx.Error(404)
			return
		}

		ctx.Repo.Repository = repo
	}
}
Exemple #4
0
func GetRepositoryByParams(ctx *context.APIContext) *models.Repository {
	repo, err := models.GetRepositoryByName(ctx.Org.Team.OrgID, ctx.Params(":reponame"))
	if err != nil {
		if models.IsErrRepoNotExist(err) {
			ctx.Status(404)
		} else {
			ctx.Error(500, "GetRepositoryByName", err)
		}
		return nil
	}
	return repo
}
Exemple #5
0
func parseOwnerAndRepo(ctx *context.APIContext) (*models.User, *models.Repository) {
	owner, err := models.GetUserByName(ctx.Params(":username"))
	if err != nil {
		if models.IsErrUserNotExist(err) {
			ctx.Error(422, "", err)
		} else {
			ctx.Error(500, "GetUserByName", err)
		}
		return nil, nil
	}

	repo, err := models.GetRepositoryByName(owner.ID, ctx.Params(":reponame"))
	if err != nil {
		if models.IsErrRepoNotExist(err) {
			ctx.Status(404)
		} else {
			ctx.Error(500, "GetRepositoryByName", err)
		}
		return nil, nil
	}

	return owner, repo
}
Exemple #6
0
func RepoAssignment(redirect bool, args ...bool) macaron.Handler {
	return func(ctx *Context) {
		var (
			displayBare bool // To display bare page if it is a bare repo.
		)
		if len(args) >= 1 {
			displayBare = args[0]
		}

		var (
			u   *models.User
			err error
		)

		userName := ctx.Params(":username")
		repoName := ctx.Params(":reponame")
		refName := ctx.Params(":branchname")
		if len(refName) == 0 {
			refName = ctx.Params(":path")
		}

		// Check if the user is the same as the repository owner
		if ctx.IsSigned && ctx.User.LowerName == strings.ToLower(userName) {
			u = ctx.User
		} else {
			u, err = models.GetUserByName(userName)
			if err != nil {
				if err == models.ErrUserNotExist {
					ctx.Handle(404, "GetUserByName", err)
				} else {
					ctx.Handle(500, "GetUserByName", err)
				}
				return
			}
		}
		ctx.Repo.Owner = u

		// Get repository.
		repo, err := models.GetRepositoryByName(u.Id, repoName)
		if err != nil {
			if models.IsErrRepoNotExist(err) {
				ctx.Handle(404, "GetRepositoryByName", err)
			} else {
				ctx.Handle(500, "GetRepositoryByName", err)
			}
			return
		} else if err = repo.GetOwner(); err != nil {
			ctx.Handle(500, "GetOwner", err)
			return
		}

		mode, err := models.AccessLevel(ctx.User, repo)
		if err != nil {
			ctx.Handle(500, "AccessLevel", err)
			return
		}
		ctx.Repo.AccessMode = mode

		// Check access.
		if ctx.Repo.AccessMode == models.ACCESS_MODE_NONE {
			ctx.Handle(404, "no access right", err)
			return
		}

		ctx.Data["HasAccess"] = true

		if repo.IsMirror {
			ctx.Repo.Mirror, err = models.GetMirror(repo.Id)
			if err != nil {
				ctx.Handle(500, "GetMirror", err)
				return
			}
			ctx.Data["MirrorInterval"] = ctx.Repo.Mirror.Interval
		}

		repo.NumOpenIssues = repo.NumIssues - repo.NumClosedIssues
		repo.NumOpenMilestones = repo.NumMilestones - repo.NumClosedMilestones
		ctx.Repo.Repository = repo
		ctx.Data["IsBareRepo"] = ctx.Repo.Repository.IsBare

		gitRepo, err := git.OpenRepository(models.RepoPath(userName, repoName))
		if err != nil {
			ctx.Handle(500, "RepoAssignment Invalid repo "+models.RepoPath(userName, repoName), err)
			return
		}
		ctx.Repo.GitRepo = gitRepo
		ctx.Repo.RepoLink, err = repo.RepoLink()
		if err != nil {
			ctx.Handle(500, "RepoLink", err)
			return
		}
		ctx.Data["RepoLink"] = ctx.Repo.RepoLink

		tags, err := ctx.Repo.GitRepo.GetTags()
		if err != nil {
			ctx.Handle(500, "GetTags", err)
			return
		}
		ctx.Data["Tags"] = tags
		ctx.Repo.Repository.NumTags = len(tags)

		// Non-fork repository will not return error in this method.
		if err = repo.GetForkRepo(); err != nil {
			ctx.Handle(500, "GetForkRepo", err)
			return
		}

		ctx.Data["Title"] = u.Name + "/" + repo.Name
		ctx.Data["Repository"] = repo
		ctx.Data["Owner"] = ctx.Repo.Repository.Owner
		ctx.Data["IsRepositoryOwner"] = ctx.Repo.AccessMode >= models.ACCESS_MODE_WRITE
		ctx.Data["IsRepositoryAdmin"] = ctx.Repo.AccessMode >= models.ACCESS_MODE_ADMIN

		ctx.Data["DisableSSH"] = setting.DisableSSH
		ctx.Repo.CloneLink, err = repo.CloneLink()
		if err != nil {
			ctx.Handle(500, "CloneLink", err)
			return
		}
		ctx.Data["CloneLink"] = ctx.Repo.CloneLink

		if ctx.Query("go-get") == "1" {
			ctx.Data["GoGetImport"] = fmt.Sprintf("%s/%s/%s", setting.Domain, u.LowerName, repo.LowerName)
		}

		// repo is bare and display enable
		if ctx.Repo.Repository.IsBare {
			log.Debug("Bare repository: %s", ctx.Repo.RepoLink)
			// NOTE: to prevent templating error
			ctx.Data["BranchName"] = ""
			if displayBare {
				ctx.HTML(200, "repo/bare")
			}
			return
		}

		if ctx.IsSigned {
			ctx.Data["IsWatchingRepo"] = models.IsWatching(ctx.User.Id, repo.Id)
			ctx.Data["IsStaringRepo"] = models.IsStaring(ctx.User.Id, repo.Id)
		}

		ctx.Data["TagName"] = ctx.Repo.TagName
		brs, err := ctx.Repo.GitRepo.GetBranches()
		if err != nil {
			ctx.Handle(500, "GetBranches", err)
			return
		}
		ctx.Data["Branches"] = brs
		ctx.Data["BrancheCount"] = len(brs)

		// If not branch selected, try default one.
		// If default branch doesn't exists, fall back to some other branch.
		if ctx.Repo.BranchName == "" {
			if ctx.Repo.Repository.DefaultBranch != "" && gitRepo.IsBranchExist(ctx.Repo.Repository.DefaultBranch) {
				ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch
			} else if len(brs) > 0 {
				ctx.Repo.BranchName = brs[0]
			}
		}

		ctx.Data["BranchName"] = ctx.Repo.BranchName
		ctx.Data["CommitId"] = ctx.Repo.CommitId
	}
}
Exemple #7
0
func RepoAssignment(args ...bool) macaron.Handler {
	return func(ctx *Context) {
		var (
			displayBare bool // To display bare page if it is a bare repo.
		)
		if len(args) >= 1 {
			displayBare = args[0]
		}

		var (
			owner *models.User
			err   error
		)

		userName := ctx.Params(":username")
		repoName := ctx.Params(":reponame")
		refName := ctx.Params(":branchname")
		if len(refName) == 0 {
			refName = ctx.Params(":path")
		}

		// Check if the user is the same as the repository owner
		if ctx.IsSigned && ctx.User.LowerName == strings.ToLower(userName) {
			owner = ctx.User
		} else {
			owner, err = models.GetUserByName(userName)
			if err != nil {
				if models.IsErrUserNotExist(err) {
					if ctx.Query("go-get") == "1" {
						earlyResponseForGoGetMeta(ctx)
						return
					}
					ctx.Handle(404, "GetUserByName", err)
				} else {
					ctx.Handle(500, "GetUserByName", err)
				}
				return
			}
		}
		ctx.Repo.Owner = owner
		ctx.Data["Username"] = ctx.Repo.Owner.Name

		// Get repository.
		repo, err := models.GetRepositoryByName(owner.ID, repoName)
		if err != nil {
			if models.IsErrRepoNotExist(err) {
				if ctx.Query("go-get") == "1" {
					earlyResponseForGoGetMeta(ctx)
					return
				}
				ctx.Handle(404, "GetRepositoryByName", err)
			} else {
				ctx.Handle(500, "GetRepositoryByName", err)
			}
			return
		} else if err = repo.GetOwner(); err != nil {
			ctx.Handle(500, "GetOwner", err)
			return
		}

		// Admin has super access.
		if ctx.IsSigned && ctx.User.IsAdmin {
			ctx.Repo.AccessMode = models.ACCESS_MODE_OWNER
		} else {
			mode, err := models.AccessLevel(ctx.User, repo)
			if err != nil {
				ctx.Handle(500, "AccessLevel", err)
				return
			}
			ctx.Repo.AccessMode = mode
		}

		// Check access.
		if ctx.Repo.AccessMode == models.ACCESS_MODE_NONE {
			if ctx.Query("go-get") == "1" {
				earlyResponseForGoGetMeta(ctx)
				return
			}
			ctx.Handle(404, "no access right", err)
			return
		}
		ctx.Data["HasAccess"] = true

		if repo.IsMirror {
			ctx.Repo.Mirror, err = models.GetMirrorByRepoID(repo.ID)
			if err != nil {
				ctx.Handle(500, "GetMirror", err)
				return
			}
			ctx.Data["MirrorEnablePrune"] = ctx.Repo.Mirror.EnablePrune
			ctx.Data["MirrorInterval"] = ctx.Repo.Mirror.Interval
			ctx.Data["Mirror"] = ctx.Repo.Mirror
		}

		ctx.Repo.Repository = repo
		ctx.Data["RepoName"] = ctx.Repo.Repository.Name
		ctx.Data["IsBareRepo"] = ctx.Repo.Repository.IsBare

		gitRepo, err := git.OpenRepository(models.RepoPath(userName, repoName))
		if err != nil {
			ctx.Handle(500, "RepoAssignment Invalid repo "+models.RepoPath(userName, repoName), err)
			return
		}
		ctx.Repo.GitRepo = gitRepo
		ctx.Repo.RepoLink = repo.Link()
		ctx.Data["RepoLink"] = ctx.Repo.RepoLink
		ctx.Data["RepoRelPath"] = ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name

		tags, err := ctx.Repo.GitRepo.GetTags()
		if err != nil {
			ctx.Handle(500, "GetTags", err)
			return
		}
		ctx.Data["Tags"] = tags
		ctx.Repo.Repository.NumTags = len(tags)

		ctx.Data["Title"] = owner.Name + "/" + repo.Name
		ctx.Data["Repository"] = repo
		ctx.Data["Owner"] = ctx.Repo.Repository.Owner
		ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner()
		ctx.Data["IsRepositoryAdmin"] = ctx.Repo.IsAdmin()
		ctx.Data["IsRepositoryWriter"] = ctx.Repo.IsWriter()

		ctx.Data["DisableSSH"] = setting.SSH.Disabled
		ctx.Data["CloneLink"] = repo.CloneLink()
		ctx.Data["WikiCloneLink"] = repo.WikiCloneLink()

		if ctx.IsSigned {
			ctx.Data["IsWatchingRepo"] = models.IsWatching(ctx.User.ID, repo.ID)
			ctx.Data["IsStaringRepo"] = models.IsStaring(ctx.User.ID, repo.ID)
		}

		// repo is bare and display enable
		if ctx.Repo.Repository.IsBare {
			log.Debug("Bare repository: %s", ctx.Repo.RepoLink)
			// NOTE: to prevent templating error
			ctx.Data["BranchName"] = ""
			if displayBare {
				if !ctx.Repo.IsAdmin() {
					ctx.Flash.Info(ctx.Tr("repo.repo_is_empty"), true)
				}
				ctx.HTML(200, "repo/bare")
			}
			return
		}

		ctx.Data["TagName"] = ctx.Repo.TagName
		brs, err := ctx.Repo.GitRepo.GetBranches()
		if err != nil {
			ctx.Handle(500, "GetBranches", err)
			return
		}
		ctx.Data["Branches"] = brs
		ctx.Data["BrancheCount"] = len(brs)

		// If not branch selected, try default one.
		// If default branch doesn't exists, fall back to some other branch.
		if len(ctx.Repo.BranchName) == 0 {
			if len(ctx.Repo.Repository.DefaultBranch) > 0 && gitRepo.IsBranchExist(ctx.Repo.Repository.DefaultBranch) {
				ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch
			} else if len(brs) > 0 {
				ctx.Repo.BranchName = brs[0]
			}
		}
		ctx.Data["BranchName"] = ctx.Repo.BranchName
		ctx.Data["CommitID"] = ctx.Repo.CommitID

		if repo.IsFork {
			RetrieveBaseRepo(ctx, repo)
			if ctx.Written() {
				return
			}
		}

		// People who have push access or have fored repository can propose a new pull request.
		if ctx.Repo.IsWriter() || (ctx.IsSigned && ctx.User.HasForkedRepo(ctx.Repo.Repository.ID)) {
			// Pull request is allowed if this is a fork repository
			// and base repository accepts pull requests.
			if repo.BaseRepo != nil {
				if repo.BaseRepo.AllowsPulls() {
					ctx.Data["BaseRepo"] = repo.BaseRepo
					ctx.Repo.PullRequest.BaseRepo = repo.BaseRepo
					ctx.Repo.PullRequest.Allowed = true
					ctx.Repo.PullRequest.HeadInfo = ctx.Repo.Owner.Name + ":" + ctx.Repo.BranchName
				}
			} else {
				// Or, this is repository accepts pull requests between branches.
				if repo.AllowsPulls() {
					ctx.Data["BaseRepo"] = repo
					ctx.Repo.PullRequest.BaseRepo = repo
					ctx.Repo.PullRequest.Allowed = true
					ctx.Repo.PullRequest.SameRepo = true
					ctx.Repo.PullRequest.HeadInfo = ctx.Repo.BranchName
				}
			}
		}
		ctx.Data["PullRequestCtx"] = ctx.Repo.PullRequest

		if ctx.Query("go-get") == "1" {
			ctx.Data["GoGetImport"] = composeGoGetImport(owner.Name, repo.Name)
			prefix := setting.AppUrl + path.Join(owner.Name, repo.Name, "src", ctx.Repo.BranchName)
			ctx.Data["GoDocDirectory"] = prefix + "{/dir}"
			ctx.Data["GoDocFile"] = prefix + "{/dir}/{file}#L{line}"
		}
	}
}
Exemple #8
0
func HTTP(ctx *context.Context) {
	username := ctx.Params(":username")
	reponame := strings.TrimSuffix(ctx.Params(":reponame"), ".git")

	var isPull bool
	service := ctx.Query("service")
	if service == "git-receive-pack" ||
		strings.HasSuffix(ctx.Req.URL.Path, "git-receive-pack") {
		isPull = false
	} else if service == "git-upload-pack" ||
		strings.HasSuffix(ctx.Req.URL.Path, "git-upload-pack") {
		isPull = true
	} else {
		isPull = (ctx.Req.Method == "GET")
	}

	isWiki := false
	if strings.HasSuffix(reponame, ".wiki") {
		isWiki = true
		reponame = reponame[:len(reponame)-5]
	}

	repoUser, err := models.GetUserByName(username)
	if err != nil {
		if models.IsErrUserNotExist(err) {
			ctx.Handle(http.StatusNotFound, "GetUserByName", nil)
		} else {
			ctx.Handle(http.StatusInternalServerError, "GetUserByName", err)
		}
		return
	}

	repo, err := models.GetRepositoryByName(repoUser.ID, reponame)
	if err != nil {
		if models.IsErrRepoNotExist(err) {
			ctx.Handle(http.StatusNotFound, "GetRepositoryByName", nil)
		} else {
			ctx.Handle(http.StatusInternalServerError, "GetRepositoryByName", err)
		}
		return
	}

	// Only public pull don't need auth.
	isPublicPull := !repo.IsPrivate && isPull
	var (
		askAuth      = !isPublicPull || setting.Service.RequireSignInView
		authUser     *models.User
		authUsername string
		authPasswd   string
	)

	// check access
	if askAuth {
		authHead := ctx.Req.Header.Get("Authorization")
		if len(authHead) == 0 {
			ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=\".\"")
			ctx.Error(http.StatusUnauthorized)
			return
		}

		auths := strings.Fields(authHead)
		// currently check basic auth
		// TODO: support digit auth
		// FIXME: middlewares/context.go did basic auth check already,
		// maybe could use that one.
		if len(auths) != 2 || auths[0] != "Basic" {
			ctx.HandleText(http.StatusUnauthorized, "no basic auth and digit auth")
			return
		}
		authUsername, authPasswd, err = base.BasicAuthDecode(auths[1])
		if err != nil {
			ctx.HandleText(http.StatusUnauthorized, "no basic auth and digit auth")
			return
		}

		authUser, err = models.UserSignIn(authUsername, authPasswd)
		if err != nil {
			if !models.IsErrUserNotExist(err) {
				ctx.Handle(http.StatusInternalServerError, "UserSignIn error: %v", err)
				return
			}

			// Assume username now is a token.
			token, err := models.GetAccessTokenBySHA(authUsername)
			if err != nil {
				if models.IsErrAccessTokenNotExist(err) || models.IsErrAccessTokenEmpty(err) {
					ctx.HandleText(http.StatusUnauthorized, "invalid token")
				} else {
					ctx.Handle(http.StatusInternalServerError, "GetAccessTokenBySha", err)
				}
				return
			}
			token.Updated = time.Now()
			if err = models.UpdateAccessToken(token); err != nil {
				ctx.Handle(http.StatusInternalServerError, "UpdateAccessToken", err)
			}
			authUser, err = models.GetUserByID(token.UID)
			if err != nil {
				ctx.Handle(http.StatusInternalServerError, "GetUserByID", err)
				return
			}
		}

		if !isPublicPull {
			var tp = models.ACCESS_MODE_WRITE
			if isPull {
				tp = models.ACCESS_MODE_READ
			}

			has, err := models.HasAccess(authUser, repo, tp)
			if err != nil {
				ctx.Handle(http.StatusInternalServerError, "HasAccess", err)
				return
			} else if !has {
				if tp == models.ACCESS_MODE_READ {
					has, err = models.HasAccess(authUser, repo, models.ACCESS_MODE_WRITE)
					if err != nil {
						ctx.Handle(http.StatusInternalServerError, "HasAccess2", err)
						return
					} else if !has {
						ctx.HandleText(http.StatusForbidden, "User permission denied")
						return
					}
				} else {
					ctx.HandleText(http.StatusForbidden, "User permission denied")
					return
				}
			}

			if !isPull && repo.IsMirror {
				ctx.HandleText(http.StatusForbidden, "mirror repository is read-only")
				return
			}
		}
	}

	callback := func(rpc string, input []byte) {
		if rpc != "receive-pack" || isWiki {
			return
		}

		var lastLine int64 = 0
		for {
			head := input[lastLine : lastLine+2]
			if head[0] == '0' && head[1] == '0' {
				size, err := strconv.ParseInt(string(input[lastLine+2:lastLine+4]), 16, 32)
				if err != nil {
					log.Error(4, "%v", err)
					return
				}

				if size == 0 {
					//fmt.Println(string(input[lastLine:]))
					break
				}

				line := input[lastLine : lastLine+size]
				idx := bytes.IndexRune(line, '\000')
				if idx > -1 {
					line = line[:idx]
				}

				fields := strings.Fields(string(line))
				if len(fields) >= 3 {
					oldCommitId := fields[0][4:]
					newCommitId := fields[1]
					refFullName := fields[2]

					// FIXME: handle error.
					if err = models.PushUpdate(models.PushUpdateOptions{
						RefFullName:  refFullName,
						OldCommitID:  oldCommitId,
						NewCommitID:  newCommitId,
						PusherID:     authUser.ID,
						PusherName:   authUser.Name,
						RepoUserName: username,
						RepoName:     reponame,
					}); err == nil {
						go models.AddTestPullRequestTask(authUser, repo.ID, strings.TrimPrefix(refFullName, git.BRANCH_PREFIX), true)
					}

				}
				lastLine = lastLine + size
			} else {
				break
			}
		}
	}

	HTTPBackend(ctx, &serviceConfig{
		UploadPack:  true,
		ReceivePack: true,
		OnSucceed:   callback,
	})(ctx.Resp, ctx.Req.Request)

	runtime.GC()
}
Exemple #9
0
func Http(ctx *middleware.Context) {
	username := ctx.Params(":username")
	reponame := ctx.Params(":reponame")
	if strings.HasSuffix(reponame, ".git") {
		reponame = reponame[:len(reponame)-4]
	}

	var isPull bool
	service := ctx.Query("service")
	if service == "git-receive-pack" ||
		strings.HasSuffix(ctx.Req.URL.Path, "git-receive-pack") {
		isPull = false
	} else if service == "git-upload-pack" ||
		strings.HasSuffix(ctx.Req.URL.Path, "git-upload-pack") {
		isPull = true
	} else {
		isPull = (ctx.Req.Method == "GET")
	}

	repoUser, err := models.GetUserByName(username)
	if err != nil {
		if err == models.ErrUserNotExist {
			ctx.Handle(404, "GetUserByName", nil)
		} else {
			ctx.Handle(500, "GetUserByName", err)
		}
		return
	}

	repo, err := models.GetRepositoryByName(repoUser.Id, reponame)
	if err != nil {
		if models.IsErrRepoNotExist(err) {
			ctx.Handle(404, "GetRepositoryByName", nil)
		} else {
			ctx.Handle(500, "GetRepositoryByName", err)
		}
		return
	}

	// Only public pull don't need auth.
	isPublicPull := !repo.IsPrivate && isPull
	var (
		askAuth      = !isPublicPull || setting.Service.RequireSignInView
		authUser     *models.User
		authUsername string
		authPasswd   string
	)

	// check access
	if askAuth {
		baHead := ctx.Req.Header.Get("Authorization")
		if baHead == "" {
			authRequired(ctx)
			return
		}

		auths := strings.Fields(baHead)
		// currently check basic auth
		// TODO: support digit auth
		// FIXME: middlewares/context.go did basic auth check already,
		// maybe could use that one.
		if len(auths) != 2 || auths[0] != "Basic" {
			ctx.Handle(401, "no basic auth and digit auth", nil)
			return
		}
		authUsername, authPasswd, err = base.BasicAuthDecode(auths[1])
		if err != nil {
			ctx.Handle(401, "no basic auth and digit auth", nil)
			return
		}

		authUser, err = models.UserSignIn(authUsername, authPasswd)
		if err != nil {
			if err != models.ErrUserNotExist {
				ctx.Handle(500, "UserSignIn error: %v", err)
				return
			}

			// Assume username now is a token.
			token, err := models.GetAccessTokenBySha(authUsername)
			if err != nil {
				if err == models.ErrAccessTokenNotExist {
					ctx.Handle(401, "invalid token", nil)
				} else {
					ctx.Handle(500, "GetAccessTokenBySha", err)
				}
				return
			}
			authUser, err = models.GetUserById(token.Uid)
			if err != nil {
				ctx.Handle(500, "GetUserById", err)
				return
			}
			authUsername = authUser.Name
		}

		if !isPublicPull {
			var tp = models.ACCESS_MODE_WRITE
			if isPull {
				tp = models.ACCESS_MODE_READ
			}

			has, err := models.HasAccess(authUser, repo, tp)
			if err != nil {
				ctx.Handle(401, "no basic auth and digit auth", nil)
				return
			} else if !has {
				if tp == models.ACCESS_MODE_READ {
					has, err = models.HasAccess(authUser, repo, models.ACCESS_MODE_WRITE)
					if err != nil || !has {
						ctx.Handle(401, "no basic auth and digit auth", nil)
						return
					}
				} else {
					ctx.Handle(401, "no basic auth and digit auth", nil)
					return
				}
			}

			if !isPull && repo.IsMirror {
				ctx.Handle(401, "can't push to mirror", nil)
				return
			}
		}
	}

	callback := func(rpc string, input []byte) {
		if rpc == "receive-pack" {
			var lastLine int64 = 0

			for {
				head := input[lastLine : lastLine+2]
				if head[0] == '0' && head[1] == '0' {
					size, err := strconv.ParseInt(string(input[lastLine+2:lastLine+4]), 16, 32)
					if err != nil {
						log.Error(4, "%v", err)
						return
					}

					if size == 0 {
						//fmt.Println(string(input[lastLine:]))
						break
					}

					line := input[lastLine : lastLine+size]
					idx := bytes.IndexRune(line, '\000')
					if idx > -1 {
						line = line[:idx]
					}
					fields := strings.Fields(string(line))
					if len(fields) >= 3 {
						oldCommitId := fields[0][4:]
						newCommitId := fields[1]
						refName := fields[2]

						// FIXME: handle error.
						models.Update(refName, oldCommitId, newCommitId, authUsername, username, reponame, authUser.Id)
					}
					lastLine = lastLine + size
				} else {
					break
				}
			}
		}
	}

	HTTPBackend(&Config{
		RepoRootPath: setting.RepoRootPath,
		GitBinPath:   "git",
		UploadPack:   true,
		ReceivePack:  true,
		OnSucceed:    callback,
	})(ctx.Resp, ctx.Req.Request)

	runtime.GC()
}
Exemple #10
0
func runServ(c *cli.Context) error {
	if c.IsSet("config") {
		setting.CustomConf = c.String("config")
	}

	setup("serv.log")

	if setting.SSH.Disabled {
		println("Gogs: SSH has been disabled")
		return nil
	}

	if len(c.Args()) < 1 {
		fail("Not enough arguments", "Not enough arguments")
	}

	cmd := os.Getenv("SSH_ORIGINAL_COMMAND")
	if len(cmd) == 0 {
		println("Hi there, You've successfully authenticated, but Gogs does not provide shell access.")
		println("If this is unexpected, please log in with password and setup Gogs under another user.")
		return nil
	}

	verb, args := parseCmd(cmd)
	repoPath := strings.ToLower(strings.Trim(args, "'"))
	rr := strings.SplitN(repoPath, "/", 2)
	if len(rr) != 2 {
		fail("Invalid repository path", "Invalid repository path: %v", args)
	}
	username := strings.ToLower(rr[0])
	reponame := strings.ToLower(strings.TrimSuffix(rr[1], ".git"))

	isWiki := false
	if strings.HasSuffix(reponame, ".wiki") {
		isWiki = true
		reponame = reponame[:len(reponame)-5]
	}

	repoUser, err := models.GetUserByName(username)
	if err != nil {
		if models.IsErrUserNotExist(err) {
			fail("Repository owner does not exist", "Unregistered owner: %s", username)
		}
		fail("Internal error", "Failed to get repository owner (%s): %v", username, err)
	}

	repo, err := models.GetRepositoryByName(repoUser.ID, reponame)
	if err != nil {
		if models.IsErrRepoNotExist(err) {
			fail(accessDenied, "Repository does not exist: %s/%s", repoUser.Name, reponame)
		}
		fail("Internal error", "Failed to get repository: %v", err)
	}

	requestedMode, has := allowedCommands[verb]
	if !has {
		fail("Unknown git command", "Unknown git command %s", verb)
	}

	// Prohibit push to mirror repositories.
	if requestedMode > models.ACCESS_MODE_READ && repo.IsMirror {
		fail("mirror repository is read-only", "")
	}

	// Allow anonymous clone for public repositories.
	var (
		keyID int64
		user  *models.User
	)
	if requestedMode == models.ACCESS_MODE_WRITE || repo.IsPrivate {
		keys := strings.Split(c.Args()[0], "-")
		if len(keys) != 2 {
			fail("Key ID format error", "Invalid key argument: %s", c.Args()[0])
		}

		key, err := models.GetPublicKeyByID(com.StrTo(keys[1]).MustInt64())
		if err != nil {
			fail("Invalid key ID", "Invalid key ID[%s]: %v", c.Args()[0], err)
		}
		keyID = key.ID

		// Check deploy key or user key.
		if key.Type == models.KEY_TYPE_DEPLOY {
			if key.Mode < requestedMode {
				fail("Key permission denied", "Cannot push with deployment key: %d", key.ID)
			}
			// Check if this deploy key belongs to current repository.
			if !models.HasDeployKey(key.ID, repo.ID) {
				fail("Key access denied", "Deploy key access denied: [key_id: %d, repo_id: %d]", key.ID, repo.ID)
			}

			// Update deploy key activity.
			deployKey, err := models.GetDeployKeyByRepo(key.ID, repo.ID)
			if err != nil {
				fail("Internal error", "GetDeployKey: %v", err)
			}

			deployKey.Updated = time.Now()
			if err = models.UpdateDeployKey(deployKey); err != nil {
				fail("Internal error", "UpdateDeployKey: %v", err)
			}
		} else {
			user, err = models.GetUserByKeyID(key.ID)
			if err != nil {
				fail("internal error", "Failed to get user by key ID(%d): %v", keyID, err)
			}

			mode, err := models.AccessLevel(user, repo)
			if err != nil {
				fail("Internal error", "Fail to check access: %v", err)
			} else if mode < requestedMode {
				clientMessage := accessDenied
				if mode >= models.ACCESS_MODE_READ {
					clientMessage = "You do not have sufficient authorization for this action"
				}
				fail(clientMessage,
					"User %s does not have level %v access to repository %s",
					user.Name, requestedMode, repoPath)
			}
		}
	}

	uuid := gouuid.NewV4().String()
	os.Setenv("uuid", uuid)

	// Special handle for Windows.
	if setting.IsWindows {
		verb = strings.Replace(verb, "-", " ", 1)
	}

	var gitcmd *exec.Cmd
	verbs := strings.Split(verb, " ")
	if len(verbs) == 2 {
		gitcmd = exec.Command(verbs[0], verbs[1], repoPath)
	} else {
		gitcmd = exec.Command(verb, repoPath)
	}
	gitcmd.Dir = setting.RepoRootPath
	gitcmd.Stdout = os.Stdout
	gitcmd.Stdin = os.Stdin
	gitcmd.Stderr = os.Stderr
	if err = gitcmd.Run(); err != nil {
		fail("Internal error", "Failed to execute git command: %v", err)
	}

	if requestedMode == models.ACCESS_MODE_WRITE {
		handleUpdateTask(uuid, user, repoUser, reponame, isWiki)
	}

	// Update user key activity.
	if keyID > 0 {
		key, err := models.GetPublicKeyByID(keyID)
		if err != nil {
			fail("Internal error", "GetPublicKeyById: %v", err)
		}

		key.Updated = time.Now()
		if err = models.UpdatePublicKey(key); err != nil {
			fail("Internal error", "UpdatePublicKey: %v", err)
		}
	}

	return nil
}
Exemple #11
0
func runServ(c *cli.Context) {
	if c.IsSet("config") {
		setting.CustomConf = c.String("config")
	}
	setup("serv.log")

	fail := func(userMessage, logMessage string, args ...interface{}) {
		fmt.Fprintln(os.Stderr, "Gogs: ", userMessage)
		log.GitLogger.Fatal(2, logMessage, args...)
	}

	if len(c.Args()) < 1 {
		fail("Not enough arguments", "Not enough arugments")
	}

	keys := strings.Split(c.Args()[0], "-")
	if len(keys) != 2 {
		fail("key-id format error", "Invalid key id: %s", c.Args()[0])
	}

	keyId, err := com.StrTo(keys[1]).Int64()
	if err != nil {
		fail("key-id format error", "Invalid key id: %s", err)
	}

	user, err := models.GetUserByKeyId(keyId)
	if err != nil {
		fail("internal error", "Fail to get user by key ID(%d): %v", keyId, err)
	}

	cmd := os.Getenv("SSH_ORIGINAL_COMMAND")
	if cmd == "" {
		println("Hi", user.Name, "! You've successfully authenticated, but Gogs does not provide shell access.")
		if user.IsAdmin {
			println("If this is unexpected, please log in with password and setup Gogs under another user.")
		}
		return
	}

	verb, args := parseCmd(cmd)
	repoPath := strings.Trim(args, "'")
	rr := strings.SplitN(repoPath, "/", 2)
	if len(rr) != 2 {
		fail("Invalid repository path", "Invalide repository path: %v", args)
	}
	repoUserName := rr[0]
	repoName := strings.TrimSuffix(rr[1], ".git")

	repoUser, err := models.GetUserByName(repoUserName)
	if err != nil {
		if err == models.ErrUserNotExist {
			fail("Repository owner does not exist", "Unregistered owner: %s", repoUserName)
		}
		fail("Internal error", "Fail to get repository owner(%s): %v", repoUserName, err)
	}

	repo, err := models.GetRepositoryByName(repoUser.Id, repoName)
	if err != nil {
		if models.IsErrRepoNotExist(err) {
			if user.Id == repoUser.Id || repoUser.IsOwnedBy(user.Id) {
				fail("Repository does not exist", "Repository does not exist: %s/%s", repoUser.Name, repoName)
			} else {
				fail(_ACCESS_DENIED_MESSAGE, "Repository does not exist: %s/%s", repoUser.Name, repoName)
			}
		}
		fail("Internal error", "Fail to get repository: %v", err)
	}

	requestedMode, has := COMMANDS[verb]
	if !has {
		fail("Unknown git command", "Unknown git command %s", verb)
	}

	mode, err := models.AccessLevel(user, repo)
	if err != nil {
		fail("Internal error", "Fail to check access: %v", err)
	} else if mode < requestedMode {
		clientMessage := _ACCESS_DENIED_MESSAGE
		if mode >= models.ACCESS_MODE_READ {
			clientMessage = "You do not have sufficient authorization for this action"
		}
		fail(clientMessage,
			"User %s does not have level %v access to repository %s",
			user.Name, requestedMode, repoPath)
	}

	uuid := uuid.NewV4().String()
	os.Setenv("uuid", uuid)

	var gitcmd *exec.Cmd
	verbs := strings.Split(verb, " ")
	if len(verbs) == 2 {
		gitcmd = exec.Command(verbs[0], verbs[1], repoPath)
	} else {
		gitcmd = exec.Command(verb, repoPath)
	}
	gitcmd.Dir = setting.RepoRootPath
	gitcmd.Stdout = os.Stdout
	gitcmd.Stdin = os.Stdin
	gitcmd.Stderr = os.Stderr
	if err = gitcmd.Run(); err != nil {
		fail("Internal error", "Fail to execute git command: %v", err)
	}

	if requestedMode == models.ACCESS_MODE_WRITE {
		tasks, err := models.GetUpdateTasksByUuid(uuid)
		if err != nil {
			log.GitLogger.Fatal(2, "GetUpdateTasksByUuid: %v", err)
		}

		for _, task := range tasks {
			err = models.Update(task.RefName, task.OldCommitId, task.NewCommitId,
				user.Name, repoUserName, repoName, user.Id)
			if err != nil {
				log.GitLogger.Error(2, "Fail to update: %v", err)
			}
		}

		if err = models.DelUpdateTasksByUuid(uuid); err != nil {
			log.GitLogger.Fatal(2, "DelUpdateTasksByUuid: %v", err)
		}
	}

	// Update key activity.
	key, err := models.GetPublicKeyById(keyId)
	if err != nil {
		fail("Internal error", "GetPublicKeyById: %v", err)
	}
	key.Updated = time.Now()
	if err = models.UpdatePublicKey(key); err != nil {
		fail("Internal error", "UpdatePublicKey: %v", err)
	}
}