func Dashboard(ctx *middleware.Context) { ctx.Data["Title"] = "Dashboard" ctx.Data["PageIsUserDashboard"] = true repos, err := models.GetRepositories(&models.User{Id: ctx.User.Id}, true) if err != nil { ctx.Handle(500, "user.Dashboard", err) return } ctx.Data["MyRepos"] = repos actions, err := models.GetFeeds(ctx.User.Id, 0, false) if err != nil { ctx.Handle(500, "user.Dashboard", err) return } feeds := make([]*models.Action, 0, len(actions)) for _, act := range actions { if act.IsPrivate { if has, _ := models.HasAccess(ctx.User.Name, act.RepoUserName+"/"+act.RepoName, models.AU_READABLE); !has { continue } } feeds = append(feeds, act) } ctx.Data["Feeds"] = feeds ctx.HTML(200, "user/dashboard") }
func Dashboard(ctx *middleware.Context) { ctx.Data["Title"] = "Dashboard" ctx.Data["PageIsUserDashboard"] = true if err := ctx.User.GetOrganizations(); err != nil { ctx.Handle(500, "home.Dashboard(GetOrganizations)", err) return } ctx.Data["Orgs"] = ctx.User.Orgs ctx.Data["ContextUser"] = ctx.User var err error ctx.Data["MyRepos"], err = models.GetRepositories(ctx.User.Id, true) if err != nil { ctx.Handle(500, "home.Dashboard(GetRepositories)", err) return } ctx.Data["CollaborativeRepos"], err = models.GetCollaborativeRepos(ctx.User.Name) if err != nil { ctx.Handle(500, "home.Dashboard(GetCollaborativeRepos)", err) return } actions, err := models.GetFeeds(ctx.User.Id, 0, false) if err != nil { ctx.Handle(500, "home.Dashboard(GetFeeds)", err) return } // Check access of private repositories. feeds := make([]*models.Action, 0, len(actions)) for _, act := range actions { if act.IsPrivate { if has, _ := models.HasAccess(ctx.User.Name, act.RepoUserName+"/"+act.RepoName, models.READABLE); !has { continue } } feeds = append(feeds, act) } ctx.Data["Feeds"] = feeds ctx.HTML(200, DASHBOARD) }
func CollaborationPost(ctx *middleware.Context) { repoLink := strings.TrimPrefix(ctx.Repo.RepoLink, "/") name := strings.ToLower(ctx.Query("collaborator")) if len(name) == 0 || ctx.Repo.Owner.LowerName == name { ctx.Redirect(ctx.Req.RequestURI) return } has, err := models.HasAccess(name, repoLink, models.AU_WRITABLE) if err != nil { ctx.Handle(500, "setting.CollaborationPost(HasAccess)", err) return } else if has { ctx.Redirect(ctx.Req.RequestURI) return } u, err := models.GetUserByName(name) if err != nil { if err == models.ErrUserNotExist { ctx.Flash.Error("Given user does not exist.") ctx.Redirect(ctx.Req.RequestURI) } else { ctx.Handle(500, "setting.CollaborationPost(GetUserByName)", err) } return } if err = models.AddAccess(&models.Access{UserName: name, RepoName: repoLink, Mode: models.AU_WRITABLE}); err != nil { ctx.Handle(500, "setting.CollaborationPost(AddAccess)", err) return } if base.Service.NotifyMail { if err = mailer.SendCollaboratorMail(ctx.Render, u, ctx.User, ctx.Repo.Repository); err != nil { ctx.Handle(500, "setting.CollaborationPost(SendCollaboratorMail)", err) return } } ctx.Flash.Success("New collaborator has been added.") ctx.Redirect(ctx.Req.RequestURI) }
func Feeds(ctx *middleware.Context, form auth.FeedsForm) { actions, err := models.GetFeeds(form.UserId, form.Page*20, false) if err != nil { ctx.JSON(500, err) return } feeds := make([]string, 0, len(actions)) for _, act := range actions { if act.IsPrivate { if has, _ := models.HasAccess(ctx.User.Name, act.RepoUserName+"/"+act.RepoName, models.AU_READABLE); !has { continue } } feeds = append(feeds, fmt.Sprintf(TPL_FEED, base.ActionIcon(act.OpType), base.TimeSince(act.Created), base.ActionDesc(act))) } ctx.JSON(200, &feeds) }
func CollaborationPost(ctx *middleware.Context) { if !ctx.Repo.IsOwner { ctx.Error(404) return } repoLink := strings.TrimPrefix(ctx.Repo.RepoLink, "/") name := strings.ToLower(ctx.Query("collaborator")) if len(name) == 0 || ctx.Repo.Owner.LowerName == name { ctx.Redirect(ctx.Req.RequestURI) return } has, err := models.HasAccess(name, repoLink, models.AU_WRITABLE) if err != nil { ctx.Handle(500, "repo.CollaborationPost(HasAccess)", err) return } else if has { ctx.Redirect(ctx.Req.RequestURI) return } isExist, err := models.IsUserExist(name) if err != nil { ctx.Handle(500, "repo.CollaborationPost(IsUserExist)", err) return } else if !isExist { ctx.Flash.Error("Given user does not exist.") ctx.Redirect(ctx.Req.RequestURI) return } if err := models.AddAccess(&models.Access{UserName: name, RepoName: repoLink, Mode: models.AU_WRITABLE}); err != nil { ctx.Handle(500, "repo.CollaborationPost(AddAccess)", err) return } ctx.Flash.Success("New collaborator has been added.") ctx.Redirect(ctx.Req.RequestURI) }
func RepoAssignment(redirect bool, args ...bool) martini.Handler { return func(ctx *Context, params martini.Params) { log.Trace(fmt.Sprint(args)) // valid brachname var validBranch bool // display bare quick start if it is a bare repo var displayBare bool if len(args) >= 1 { // Note: argument has wrong value in Go1.3 martini. // validBranch = args[0] validBranch = true } if len(args) >= 2 { // displayBare = args[1] displayBare = true } var ( user *models.User err error isTrueOwner bool ) userName := params["username"] repoName := params["reponame"] refName := params["branchname"] // Collaborators who have write access can be seen as owners. if ctx.IsSigned { ctx.Repo.IsOwner, err = models.HasAccess(ctx.User.Name, userName+"/"+repoName, models.AU_WRITABLE) if err != nil { ctx.Handle(500, "RepoAssignment(HasAccess)", err) return } isTrueOwner = ctx.User.LowerName == strings.ToLower(userName) } if !isTrueOwner { user, err = models.GetUserByName(userName) if err != nil { if err == models.ErrUserNotExist { ctx.Handle(404, "RepoAssignment(GetUserByName)", err) return } else if redirect { ctx.Redirect("/") return } ctx.Handle(500, "RepoAssignment(GetUserByName)", err) return } } else { user = ctx.User } if user == nil { if redirect { ctx.Redirect("/") return } ctx.Handle(403, "RepoAssignment", errors.New("invliad user account for single repository")) return } ctx.Repo.Owner = user // get repository repo, err := models.GetRepositoryByName(user.Id, repoName) if err != nil { if err == models.ErrRepoNotExist { ctx.Handle(404, "RepoAssignment", err) return } else if redirect { ctx.Redirect("/") return } ctx.Handle(500, "RepoAssignment", err) return } // Check access. if repo.IsPrivate && !ctx.Repo.IsOwner { if ctx.User == nil { ctx.Handle(404, "RepoAssignment(HasAccess)", nil) return } hasAccess, err := models.HasAccess(ctx.User.Name, ctx.Repo.Owner.Name+"/"+repo.Name, models.AU_READABLE) if err != nil { ctx.Handle(500, "RepoAssignment(HasAccess)", err) return } else if !hasAccess { ctx.Handle(404, "RepoAssignment(HasAccess)", nil) return } } ctx.Repo.HasAccess = true ctx.Data["HasAccess"] = true if repo.IsMirror { ctx.Repo.Mirror, err = models.GetMirror(repo.Id) if err != nil { ctx.Handle(500, "RepoAssignment(GetMirror)", err) return } ctx.Data["MirrorInterval"] = ctx.Repo.Mirror.Interval } repo.NumOpenIssues = repo.NumIssues - repo.NumClosedIssues 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 = "/" + user.Name + "/" + repo.Name tags, err := ctx.Repo.GitRepo.GetTags() if err != nil { ctx.Handle(500, "RepoAssignment(GetTags))", err) return } ctx.Repo.Repository.NumTags = len(tags) ctx.Data["Title"] = user.Name + "/" + repo.Name ctx.Data["Repository"] = repo ctx.Data["Owner"] = user ctx.Data["RepoLink"] = ctx.Repo.RepoLink ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner ctx.Data["BranchName"] = "" if base.SshPort != 22 { ctx.Repo.CloneLink.SSH = fmt.Sprintf("ssh://%s@%s/%s/%s.git", base.RunUser, base.Domain, user.LowerName, repo.LowerName) } else { ctx.Repo.CloneLink.SSH = fmt.Sprintf("%s@%s:%s/%s.git", base.RunUser, base.Domain, user.LowerName, repo.LowerName) } ctx.Repo.CloneLink.HTTPS = fmt.Sprintf("%s%s/%s.git", base.AppUrl, user.LowerName, repo.LowerName) ctx.Data["CloneLink"] = ctx.Repo.CloneLink if ctx.Repo.Repository.IsGoget { ctx.Data["GoGetLink"] = fmt.Sprintf("%s%s/%s", base.AppUrl, user.LowerName, repo.LowerName) ctx.Data["GoGetImport"] = fmt.Sprintf("%s/%s/%s", base.Domain, user.LowerName, repo.LowerName) } // when repo is bare, not valid branch if !ctx.Repo.Repository.IsBare && validBranch { detect: if len(refName) > 0 { if gitRepo.IsBranchExist(refName) { ctx.Repo.IsBranch = true ctx.Repo.BranchName = refName ctx.Repo.Commit, err = gitRepo.GetCommitOfBranch(refName) if err != nil { ctx.Handle(404, "RepoAssignment invalid branch", nil) return } ctx.Repo.CommitId = ctx.Repo.Commit.Id.String() } else if gitRepo.IsTagExist(refName) { ctx.Repo.IsBranch = true ctx.Repo.BranchName = refName ctx.Repo.Commit, err = gitRepo.GetCommitOfTag(refName) if err != nil { ctx.Handle(404, "RepoAssignment invalid tag", nil) return } ctx.Repo.CommitId = ctx.Repo.Commit.Id.String() } else if len(refName) == 40 { ctx.Repo.IsCommit = true ctx.Repo.CommitId = refName ctx.Repo.BranchName = refName ctx.Repo.Commit, err = gitRepo.GetCommit(refName) if err != nil { ctx.Handle(404, "RepoAssignment invalid commit", nil) return } } else { ctx.Handle(404, "RepoAssignment invalid repo", nil) return } } else { if len(refName) == 0 { if gitRepo.IsBranchExist(ctx.Repo.Repository.DefaultBranch) { refName = ctx.Repo.Repository.DefaultBranch } else { brs, err := gitRepo.GetBranches() if err != nil { ctx.Handle(500, "RepoAssignment(GetBranches))", err) return } refName = brs[0] } } goto detect } ctx.Data["IsBranch"] = ctx.Repo.IsBranch ctx.Data["IsCommit"] = ctx.Repo.IsCommit log.Debug("Repo.Commit: %v", ctx.Repo.Commit) } log.Debug("displayBare: %v; IsBare: %v", displayBare, ctx.Repo.Repository.IsBare) // repo is bare and display enable if displayBare && ctx.Repo.Repository.IsBare { log.Debug("Bare repository: %s", ctx.Repo.RepoLink) ctx.HTML(200, "repo/single_bare") return } if ctx.IsSigned { ctx.Repo.IsWatching = models.IsWatching(ctx.User.Id, repo.Id) } ctx.Data["BranchName"] = ctx.Repo.BranchName brs, err := ctx.Repo.GitRepo.GetBranches() if err != nil { log.Error("RepoAssignment(GetBranches): %v", err) } ctx.Data["Branches"] = brs ctx.Data["CommitId"] = ctx.Repo.CommitId ctx.Data["IsRepositoryWatching"] = ctx.Repo.IsWatching } }
func RepoAssignment(redirect bool, args ...bool) macaron.Handler { return func(ctx *Context) { var ( validBranch bool // To valid brach name. displayBare bool // To display bare page if it is a bare repo. ) if len(args) >= 1 { validBranch = args[0] } if len(args) >= 2 { displayBare = args[1] } 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") } // Collaborators who have write access can be seen as owners. if ctx.IsSigned { ctx.Repo.IsOwner, err = models.HasAccess(ctx.User.Name, userName+"/"+repoName, models.WRITABLE) if err != nil { ctx.Handle(500, "HasAccess", err) return } ctx.Repo.IsTrueOwner = ctx.User.LowerName == strings.ToLower(userName) } if !ctx.Repo.IsTrueOwner { u, err = models.GetUserByName(userName) if err != nil { if err == models.ErrUserNotExist { ctx.Handle(404, "GetUserByName", err) } else if redirect { log.Error(4, "GetUserByName", err) ctx.Redirect("/") } else { ctx.Handle(500, "GetUserByName", err) } return } } else { u = ctx.User } if u == nil { if redirect { ctx.Redirect("/") return } ctx.Handle(404, "RepoAssignment", errors.New("invliad user account for single repository")) return } ctx.Repo.Owner = u // Organization owner team members are true owners as well. if ctx.IsSigned && ctx.Repo.Owner.IsOrganization() && ctx.Repo.Owner.IsOrgOwner(ctx.User.Id) { ctx.Repo.IsTrueOwner = true } // Get repository. repo, err := models.GetRepositoryByName(u.Id, repoName) if err != nil { if err == models.ErrRepoNotExist { ctx.Handle(404, "GetRepositoryByName", err) return } else if redirect { ctx.Redirect("/") return } ctx.Handle(500, "GetRepositoryByName", err) return } else if err = repo.GetOwner(); err != nil { ctx.Handle(500, "GetOwner", err) return } // Check if the mirror repository owner(mirror repository doesn't have access). if ctx.IsSigned && !ctx.Repo.IsOwner { if repo.OwnerId == ctx.User.Id { ctx.Repo.IsOwner = true } // Check if current user has admin permission to repository. if u.IsOrganization() { auth, err := models.GetHighestAuthorize(u.Id, ctx.User.Id, 0, repo.Id) if err != nil { ctx.Handle(500, "GetHighestAuthorize", err) return } if auth == models.ORG_ADMIN { ctx.Repo.IsOwner = true ctx.Repo.IsAdmin = true } } } // Check access. if repo.IsPrivate && !ctx.Repo.IsOwner { if ctx.User == nil { ctx.Handle(404, "HasAccess", nil) return } hasAccess, err := models.HasAccess(ctx.User.Name, ctx.Repo.Owner.Name+"/"+repo.Name, models.READABLE) if err != nil { ctx.Handle(500, "HasAccess", err) return } else if !hasAccess { ctx.Handle(404, "HasAccess", nil) return } } ctx.Repo.HasAccess = true 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 = "/" + u.Name + "/" + repo.Name ctx.Data["RepoLink"] = ctx.Repo.RepoLink tags, err := ctx.Repo.GitRepo.GetTags() if err != nil { ctx.Handle(500, "GetTags", err) return } ctx.Repo.Repository.NumTags = len(tags) ctx.Data["Title"] = u.Name + "/" + repo.Name ctx.Data["Repository"] = repo ctx.Data["Owner"] = ctx.Repo.Repository.Owner ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner ctx.Data["IsRepositoryTrueOwner"] = ctx.Repo.IsTrueOwner if setting.SshPort != 22 { ctx.Repo.CloneLink.SSH = fmt.Sprintf("ssh://%s@%s:%d/%s/%s.git", setting.RunUser, setting.Domain, setting.SshPort, u.LowerName, repo.LowerName) } else { ctx.Repo.CloneLink.SSH = fmt.Sprintf("%s@%s:%s/%s.git", setting.RunUser, setting.Domain, u.LowerName, repo.LowerName) } ctx.Repo.CloneLink.HTTPS = fmt.Sprintf("%s%s/%s.git", setting.AppUrl, u.LowerName, repo.LowerName) ctx.Data["CloneLink"] = ctx.Repo.CloneLink if ctx.Repo.Repository.IsGoget { ctx.Data["GoGetLink"] = fmt.Sprintf("%s%s/%s", setting.AppUrl, u.LowerName, repo.LowerName) ctx.Data["GoGetImport"] = fmt.Sprintf("%s/%s/%s", setting.Domain, u.LowerName, repo.LowerName) } // when repo is bare, not valid branch if !ctx.Repo.Repository.IsBare && validBranch { detect: if len(refName) > 0 { if gitRepo.IsBranchExist(refName) { ctx.Repo.IsBranch = true ctx.Repo.BranchName = refName ctx.Repo.Commit, err = gitRepo.GetCommitOfBranch(refName) if err != nil { ctx.Handle(404, "RepoAssignment invalid branch", nil) return } ctx.Repo.CommitId = ctx.Repo.Commit.Id.String() } else if gitRepo.IsTagExist(refName) { ctx.Repo.IsTag = true ctx.Repo.BranchName = refName ctx.Repo.Tag, err = gitRepo.GetTag(refName) if err != nil { ctx.Handle(404, "RepoAssignment invalid tag", nil) return } ctx.Repo.Commit, _ = ctx.Repo.Tag.Commit() ctx.Repo.CommitId = ctx.Repo.Commit.Id.String() } else if len(refName) == 40 { ctx.Repo.IsCommit = true ctx.Repo.CommitId = refName ctx.Repo.BranchName = refName ctx.Repo.Commit, err = gitRepo.GetCommit(refName) if err != nil { ctx.Handle(404, "RepoAssignment invalid commit", nil) return } } else { ctx.Handle(404, "RepoAssignment invalid repo", errors.New("branch or tag not exist")) return } } else { if len(refName) == 0 { if gitRepo.IsBranchExist(ctx.Repo.Repository.DefaultBranch) { refName = ctx.Repo.Repository.DefaultBranch } else { brs, err := gitRepo.GetBranches() if err != nil { ctx.Handle(500, "GetBranches", err) return } refName = brs[0] } } goto detect } ctx.Data["IsBranch"] = ctx.Repo.IsBranch ctx.Data["IsCommit"] = ctx.Repo.IsCommit ctx.Repo.CommitsCount, err = ctx.Repo.Commit.CommitsCount() if err != nil { ctx.Handle(500, "CommitsCount", err) return } ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount } // repo is bare and display enable if ctx.Repo.Repository.IsBare { log.Debug("Bare repository: %s", ctx.Repo.RepoLink) 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 { log.Error(4, "GetBranches: %v", err) } 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 } }
func runServ(k *cli.Context) { setup("serv.log") keys := strings.Split(os.Args[2], "-") if len(keys) != 2 { println("Gogs: auth file format error") log.GitLogger.Fatal(2, "Invalid auth file format: %s", os.Args[2]) } keyId, err := com.StrTo(keys[1]).Int64() if err != nil { println("Gogs: auth file format error") log.GitLogger.Fatal(2, "Invalid auth file format: %v", err) } user, err := models.GetUserByKeyId(keyId) if err != nil { if err == models.ErrUserNotKeyOwner { println("Gogs: you are not the owner of SSH key") log.GitLogger.Fatal(2, "Invalid owner of SSH key: %d", keyId) } println("Gogs: internal error:", err) log.GitLogger.Fatal(2, "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.") return } verb, args := parseCmd(cmd) repoPath := strings.Trim(args, "'") rr := strings.SplitN(repoPath, "/", 2) if len(rr) != 2 { println("Gogs: unavailable repository", args) log.GitLogger.Fatal(2, "Unavailable repository: %v", args) } repoUserName := rr[0] repoName := strings.TrimSuffix(rr[1], ".git") isWrite := In(verb, COMMANDS_WRITE) isRead := In(verb, COMMANDS_READONLY) repoUser, err := models.GetUserByName(repoUserName) if err != nil { if err == models.ErrUserNotExist { println("Gogs: given repository owner are not registered") log.GitLogger.Fatal(2, "Unregistered owner: %s", repoUserName) } println("Gogs: internal error:", err) log.GitLogger.Fatal(2, "Fail to get repository owner(%s): %v", repoUserName, err) } // Access check. switch { case isWrite: has, err := models.HasAccess(user.Name, path.Join(repoUserName, repoName), models.WRITABLE) if err != nil { println("Gogs: internal error:", err) log.GitLogger.Fatal(2, "Fail to check write access:", err) } else if !has { println("You have no right to write this repository") log.GitLogger.Fatal(2, "User %s has no right to write repository %s", user.Name, repoPath) } case isRead: repo, err := models.GetRepositoryByName(repoUser.Id, repoName) if err != nil { if err == models.ErrRepoNotExist { println("Gogs: given repository does not exist") log.GitLogger.Fatal(2, "Repository does not exist: %s/%s", repoUser.Name, repoName) } println("Gogs: internal error:", err) log.GitLogger.Fatal(2, "Fail to get repository: %v", err) } if !repo.IsPrivate { break } has, err := models.HasAccess(user.Name, path.Join(repoUserName, repoName), models.READABLE) if err != nil { println("Gogs: internal error:", err) log.GitLogger.Fatal(2, "Fail to check read access:", err) } else if !has { println("You have no right to access this repository") log.GitLogger.Fatal(2, "User %s has no right to read repository %s", user.Name, repoPath) } default: println("Unknown command") return } uuid := uuid.NewV4().String() os.Setenv("uuid", uuid) 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 { println("Gogs: internal error:", err.Error()) log.GitLogger.Fatal(2, "Fail to execute git command: %v", err) } if isWrite { 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 { log.GitLogger.Fatal(2, "GetPublicKeyById: %v", err) } key.Updated = time.Now() if err = models.UpdatePublicKey(key); err != nil { log.GitLogger.Fatal(2, "UpdatePublicKey: %v", err) } }
func runServ(k *cli.Context) { setup(path.Join(setting.LogRootPath, "serv.log")) keys := strings.Split(os.Args[2], "-") if len(keys) != 2 { println("Gogs: auth file format error") qlog.Fatal("Invalid auth file format: %s", os.Args[2]) } keyId, err := strconv.ParseInt(keys[1], 10, 64) if err != nil { println("Gogs: auth file format error") qlog.Fatalf("Invalid auth file format: %v", err) } user, err := models.GetUserByKeyId(keyId) if err != nil { if err == models.ErrUserNotKeyOwner { println("Gogs: you are not the owner of SSH key") qlog.Fatalf("Invalid owner of SSH key: %d", keyId) } println("Gogs: internal error:", err) qlog.Fatalf("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.") return } verb, args := parseCmd(cmd) repoPath := strings.Trim(args, "'") rr := strings.SplitN(repoPath, "/", 2) if len(rr) != 2 { println("Gogs: unavailable repository", args) qlog.Fatalf("Unavailable repository: %v", args) } repoUserName := rr[0] repoName := strings.TrimSuffix(rr[1], ".git") isWrite := In(verb, COMMANDS_WRITE) isRead := In(verb, COMMANDS_READONLY) repoUser, err := models.GetUserByName(repoUserName) if err != nil { if err == models.ErrUserNotExist { println("Gogs: given repository owner are not registered") qlog.Fatalf("Unregistered owner: %s", repoUserName) } println("Gogs: internal error:", err) qlog.Fatalf("Fail to get repository owner(%s): %v", repoUserName, err) } // Access check. switch { case isWrite: has, err := models.HasAccess(user.Name, path.Join(repoUserName, repoName), models.AU_WRITABLE) if err != nil { println("Gogs: internal error:", err) qlog.Fatal("Fail to check write access:", err) } else if !has { println("You have no right to write this repository") qlog.Fatalf("User %s has no right to write repository %s", user.Name, repoPath) } case isRead: repo, err := models.GetRepositoryByName(repoUser.Id, repoName) if err != nil { if err == models.ErrRepoNotExist { println("Gogs: given repository does not exist") qlog.Fatalf("Repository does not exist: %s/%s", repoUser.Name, repoName) } println("Gogs: internal error:", err) qlog.Fatalf("Fail to get repository: %v", err) } if !repo.IsPrivate { break } has, err := models.HasAccess(user.Name, path.Join(repoUserName, repoName), models.AU_READABLE) if err != nil { println("Gogs: internal error:", err) qlog.Fatal("Fail to check read access:", err) } else if !has { println("You have no right to access this repository") qlog.Fatalf("User %s has no right to read repository %s", user.Name, repoPath) } default: println("Unknown command") return } models.SetRepoEnvs(user.Id, user.Name, repoName, repoUserName) 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 { println("Gogs: internal error:", err) qlog.Fatalf("Fail to execute git command: %v", err) } //refName := os.Getenv("refName") //oldCommitId := os.Getenv("oldCommitId") //newCommitId := os.Getenv("newCommitId") //qlog.Error("get envs:", refName, oldCommitId, newCommitId) // update //models.Update(refName, oldCommitId, newCommitId, repoUserName, repoName, user.Id) }
func Dashboard(ctx *middleware.Context) { ctx.Data["Title"] = ctx.Tr("dashboard") ctx.Data["PageIsDashboard"] = true ctx.Data["PageIsNews"] = true var ctxUser *models.User // Check context type. orgName := ctx.Params(":org") if len(orgName) > 0 { // Organization. org, err := models.GetUserByName(orgName) if err != nil { if err == models.ErrUserNotExist { ctx.Handle(404, "GetUserByName", err) } else { ctx.Handle(500, "GetUserByName", err) } return } ctxUser = org } else { // Normal user. ctxUser = ctx.User collaborates, err := models.GetCollaborativeRepos(ctxUser.Name) if err != nil { ctx.Handle(500, "GetCollaborativeRepos", err) return } ctx.Data["CollaborateCount"] = len(collaborates) ctx.Data["CollaborativeRepos"] = collaborates } ctx.Data["ContextUser"] = ctxUser if err := ctx.User.GetOrganizations(); err != nil { ctx.Handle(500, "GetOrganizations", err) return } ctx.Data["Orgs"] = ctx.User.Orgs repos, err := models.GetRepositories(ctxUser.Id, true) if err != nil { ctx.Handle(500, "GetRepositories", err) return } ctx.Data["Repos"] = repos // Get mirror repositories. mirrors := make([]*models.Repository, 0, len(repos)/2) for _, repo := range repos { if repo.IsMirror { if err = repo.GetMirror(); err != nil { ctx.Handle(500, "GetMirror: "+repo.Name, err) return } mirrors = append(mirrors, repo) } } ctx.Data["MirrorCount"] = len(mirrors) ctx.Data["Mirrors"] = mirrors // Get feeds. actions, err := models.GetFeeds(ctxUser.Id, 0, false) if err != nil { ctx.Handle(500, "GetFeeds", err) return } // Check access of private repositories. feeds := make([]*models.Action, 0, len(actions)) for _, act := range actions { if act.IsPrivate { if has, _ := models.HasAccess(ctxUser.Name, act.RepoUserName+"/"+act.RepoName, models.READABLE); !has { continue } } feeds = append(feeds, act) } ctx.Data["Feeds"] = feeds ctx.HTML(200, DASHBOARD) }
func Http(ctx *middleware.Context, params martini.Params) { username := params["username"] reponame := 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, "repo.Http(GetUserByName)", nil) } else { ctx.Handle(500, "repo.Http(GetUserByName)", nil) } return } repo, err := models.GetRepositoryByName(repoUser.Id, reponame) if err != nil { if err == models.ErrRepoNotExist { ctx.Handle(404, "repo.Http(GetRepositoryByName)", nil) } else { ctx.Handle(500, "repo.Http(GetRepositoryByName)", nil) } return } // only public pull don't need auth isPublicPull := !repo.IsPrivate && isPull var askAuth = !isPublicPull || setting.Service.RequireSignInView var authUser *models.User var authUsername, passwd string // check access if askAuth { baHead := ctx.Req.Header.Get("Authorization") if baHead == "" { // ask auth authRequired(ctx) return } auths := strings.Fields(baHead) // currently check basic auth // TODO: support digit auth if len(auths) != 2 || auths[0] != "Basic" { ctx.Handle(401, "no basic auth and digit auth", nil) return } authUsername, passwd, err = basicDecode(auths[1]) if err != nil { ctx.Handle(401, "no basic auth and digit auth", nil) return } authUser, err = models.GetUserByName(authUsername) if err != nil { ctx.Handle(401, "no basic auth and digit auth", nil) return } newUser := &models.User{Passwd: passwd, Salt: authUser.Salt} newUser.EncodePasswd() if authUser.Passwd != newUser.Passwd { ctx.Handle(401, "no basic auth and digit auth", nil) return } if !isPublicPull { var tp = models.WRITABLE if isPull { tp = models.READABLE } has, err := models.HasAccess(authUsername, username+"/"+reponame, tp) if err != nil { ctx.Handle(401, "no basic auth and digit auth", nil) return } else if !has { if tp == models.READABLE { has, err = models.HasAccess(authUsername, username+"/"+reponame, models.WRITABLE) 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 } } } } var f func(rpc string, input []byte) f = 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("%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] models.Update(refName, oldCommitId, newCommitId, authUsername, username, reponame, authUser.Id) } lastLine = lastLine + size } else { //fmt.Println("ddddddddddd") break } } } } config := Config{setting.RepoRootPath, "git", true, true, f} handler := HttpBackend(&config) handler(ctx.ResponseWriter, ctx.Req) }
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 models.IsErrUserNotExist(err) { 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.HandleText(401, "no basic auth and digit auth") return } authUsername, authPasswd, err = base.BasicAuthDecode(auths[1]) if err != nil { ctx.HandleText(401, "no basic auth and digit auth") return } authUser, err = models.UserSignIn(authUsername, authPasswd) if err != nil { if !models.IsErrUserNotExist(err) { 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.HandleText(401, "invalid token") } 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.HandleText(401, "no basic auth and digit auth") 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.HandleText(401, "no basic auth and digit auth") return } } else { ctx.HandleText(401, "no basic auth and digit auth") return } } if !isPull && repo.IsMirror { ctx.HandleText(401, "can't push to mirror") 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. if err = models.Update(refName, oldCommitId, newCommitId, authUsername, username, reponame, authUser.Id); err == nil { models.HookQueue.AddRepoID(repo.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() }
func Dashboard(ctx *middleware.Context) { ctx.Data["Title"] = ctx.Tr("dashboard") ctx.Data["PageIsDashboard"] = true ctx.Data["PageIsNews"] = true ctxUser := getDashboardContextUser(ctx) if ctx.Written() { return } // Check context type. if !ctxUser.IsOrganization() { // Normal user. ctxUser = ctx.User collaborates, err := ctx.User.GetAccessibleRepositories() if err != nil { ctx.Handle(500, "GetAccessibleRepositories", err) return } repositories := make([]*models.Repository, 0, len(collaborates)) for repo := range collaborates { repositories = append(repositories, repo) } ctx.Data["CollaborateCount"] = len(repositories) ctx.Data["CollaborativeRepos"] = repositories } repos, err := models.GetRepositories(ctxUser.Id, true) if err != nil { ctx.Handle(500, "GetRepositories", err) return } ctx.Data["Repos"] = repos // Get mirror repositories. mirrors := make([]*models.Repository, 0, len(repos)/2) for _, repo := range repos { if repo.IsMirror { if err = repo.GetMirror(); err != nil { ctx.Handle(500, "GetMirror: "+repo.Name, err) return } mirrors = append(mirrors, repo) } } ctx.Data["MirrorCount"] = len(mirrors) ctx.Data["Mirrors"] = mirrors // Get feeds. actions, err := models.GetFeeds(ctxUser.Id, 0, false) if err != nil { ctx.Handle(500, "GetFeeds", err) return } // Check access of private repositories. feeds := make([]*models.Action, 0, len(actions)) for _, act := range actions { if act.IsPrivate { // This prevents having to retrieve the repository for each action repo := &models.Repository{ID: act.RepoID, IsPrivate: true} if act.RepoUserName != ctx.User.LowerName { if has, _ := models.HasAccess(ctx.User, repo, models.ACCESS_MODE_READ); !has { continue } } } // FIXME: cache results? u, err := models.GetUserByName(act.ActUserName) if err != nil { if models.IsErrUserNotExist(err) { continue } ctx.Handle(500, "GetUserByName", err) return } act.ActAvatar = u.AvatarLink() feeds = append(feeds, act) } ctx.Data["Feeds"] = feeds ctx.HTML(200, DASHBOARD) }
func Profile(ctx *middleware.Context) { ctx.Data["Title"] = "Profile" ctx.Data["PageIsUserProfile"] = true uname := ctx.Params(":username") // Special handle for FireFox requests favicon.ico. if uname == "favicon.ico" { ctx.Redirect(setting.AppSubUrl + "/img/favicon.png") return } isShowKeys := false if strings.HasSuffix(uname, ".keys") { isShowKeys = true uname = strings.TrimSuffix(uname, ".keys") } u, err := models.GetUserByName(uname) if err != nil { if models.IsErrUserNotExist(err) { ctx.Handle(404, "GetUserByName", err) } else { ctx.Handle(500, "GetUserByName", err) } return } // Show SSH keys. if isShowKeys { ShowSSHKeys(ctx, u.Id) return } if u.IsOrganization() { ctx.Redirect(setting.AppSubUrl + "/org/" + u.Name) return } ctx.Data["Owner"] = u tab := ctx.Query("tab") ctx.Data["TabName"] = tab switch tab { case "activity": actions, err := models.GetFeeds(u.Id, 0, false) if err != nil { ctx.Handle(500, "GetFeeds", err) return } feeds := make([]*models.Action, 0, len(actions)) for _, act := range actions { if act.IsPrivate { if !ctx.IsSigned { continue } // This prevents having to retrieve the repository for each action repo := &models.Repository{ID: act.RepoID, IsPrivate: true} if act.RepoUserName != ctx.User.LowerName { if has, _ := models.HasAccess(ctx.User, repo, models.ACCESS_MODE_READ); !has { continue } } } // FIXME: cache results? u, err := models.GetUserByName(act.ActUserName) if err != nil { if models.IsErrUserNotExist(err) { continue } ctx.Handle(500, "GetUserByName", err) return } act.ActAvatar = u.AvatarLink() feeds = append(feeds, act) } ctx.Data["Feeds"] = feeds default: ctx.Data["Repos"], err = models.GetRepositories(u.Id, ctx.IsSigned && ctx.User.Id == u.Id) if err != nil { ctx.Handle(500, "GetRepositories", err) return } } ctx.HTML(200, PROFILE) }
func runServ(k *cli.Context) { base.NewConfigContext() models.LoadModelsConfig() models.NewEngine() keys := strings.Split(os.Args[2], "-") if len(keys) != 2 { fmt.Println("auth file format error") return } keyId, err := strconv.ParseInt(keys[1], 10, 64) if err != nil { fmt.Println("auth file format error") return } user, err := models.GetUserByKeyId(keyId) if err != nil { fmt.Println("You have no right to access") return } cmd := os.Getenv("SSH_ORIGINAL_COMMAND") if cmd == "" { println("Hi", user.Name, "! You've successfully authenticated, but Gogs does not provide shell access.") return } verb, args := parseCmd(cmd) rRepo := strings.Trim(args, "'") rr := strings.SplitN(rRepo, "/", 2) if len(rr) != 2 { println("Unavilable repository", args) return } repoName := rr[1] if strings.HasSuffix(repoName, ".git") { repoName = repoName[:len(repoName)-4] } repo, err := models.GetRepositoryByName(user.Id, repoName) var isExist bool = true if err != nil { if err == models.ErrRepoNotExist { isExist = false } else { println("Unavilable repository", err) return } } isWrite := In(verb, COMMANDS_WRITE) isRead := In(verb, COMMANDS_READONLY) switch { case isWrite: has, err := models.HasAccess(user.Name, repoName, models.AU_WRITABLE) if err != nil { println("Inernel error:", err) return } if !has { println("You have no right to write this repository") return } case isRead: has, err := models.HasAccess(user.Name, repoName, models.AU_READABLE) if err != nil { println("Inernel error") return } if !has { has, err = models.HasAccess(user.Name, repoName, models.AU_WRITABLE) if err != nil { println("Inernel error") return } } if !has { println("You have no right to access this repository") return } default: println("Unknown command") return } if !isExist { if isRead { println("Repository", user.Name+"/"+repoName, "is not exist") return } else if isWrite { _, err := models.CreateRepository(user, repoName, "", "", "", false, true) if err != nil { println("Create repository failed") return } } } rep, err := git.OpenRepository(models.RepoPath(user.Name, repoName)) if err != nil { println(err.Error()) return } refs, err := rep.AllReferencesMap() if err != nil { println(err.Error()) return } gitcmd := exec.Command(verb, rRepo) gitcmd.Dir = base.RepoRootPath var s string b := bytes.NewBufferString(s) gitcmd.Stdout = io.MultiWriter(os.Stdout, b) //gitcmd.Stdin = io.MultiReader(os.Stdin, b) gitcmd.Stdin = os.Stdin gitcmd.Stderr = os.Stderr if err = gitcmd.Run(); err != nil { println("execute command error:", err.Error()) } if !strings.HasPrefix(cmd, "git-receive-pack") { return } // update //w, _ := os.Create("serve.log") //defer w.Close() //log.SetOutput(w) var t = "ok refs/heads/" var i int var refname string for { l, err := b.ReadString('\n') if err != nil { break } i = i + 1 l = l[:len(l)-1] idx := strings.Index(l, t) if idx > 0 { refname = l[idx+len(t):] } } var ref *git.Reference var ok bool var l *list.List //log.Info("----", refname, "-----") if ref, ok = refs[refname]; !ok { refs, err = rep.AllReferencesMap() if err != nil { println(err.Error()) return } if ref, ok = refs[refname]; !ok { println("unknow reference name -", refname, "-") return } l, err = ref.AllCommits() if err != nil { println(err.Error()) return } } else { //log.Info("----", ref, "-----") var last *git.Commit //log.Info("00000", ref.Oid.String()) last, err = ref.LastCommit() if err != nil { println(err.Error()) return } ref2, err := rep.LookupReference(ref.Name) if err != nil { println(err.Error()) return } //log.Info("11111", ref2.Oid.String()) before, err := ref2.LastCommit() if err != nil { println(err.Error()) return } //log.Info("----", before.Id(), "-----", last.Id()) l = ref.CommitsBetween(before, last) } commits := make([][]string, 0) var maxCommits = 3 for e := l.Front(); e != nil; e = e.Next() { commit := e.Value.(*git.Commit) commits = append(commits, []string{commit.Id().String(), commit.Message()}) if len(commits) >= maxCommits { break } } if err = models.CommitRepoAction(user.Id, user.Name, repo.Id, repoName, refname, &base.PushCommits{l.Len(), commits}); err != nil { log.Error("runUpdate.models.CommitRepoAction: %v", err, commits) } else { //log.Info("refname", refname) //log.Info("Listen: %v", cmd) //fmt.Println("...", cmd) //runUpdate(k) c := exec.Command("git", "update-server-info") c.Dir = models.RepoPath(user.Name, repoName) err := c.Run() if err != nil { log.Error("update-server-info: %v", err) } } }
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) { 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] refName := fields[2] // FIXME: handle error. if err = models.PushUpdate(models.PushUpdateOptions{ RefName: refName, OldCommitID: oldCommitId, NewCommitID: newCommitId, PusherID: authUser.Id, PusherName: authUser.Name, RepoUserName: username, RepoName: reponame, }); err == nil { go models.HookQueue.Add(repo.ID) go models.AddTestPullRequestTask(repo.ID, strings.TrimPrefix(refName, "refs/heads/")) } } lastLine = lastLine + size } else { break } } } HTTPBackend(ctx, &serviceConfig{ UploadPack: true, ReceivePack: true, OnSucceed: callback, })(ctx.Resp, ctx.Req.Request) runtime.GC() }
func SettingsCollaboration(ctx *middleware.Context) { ctx.Data["Title"] = ctx.Tr("repo.settings") ctx.Data["PageIsSettingsCollaboration"] = true repoLink := strings.TrimPrefix(ctx.Repo.RepoLink, "/") if ctx.Req.Method == "POST" { name := strings.ToLower(ctx.Query("collaborator")) if len(name) == 0 || ctx.Repo.Owner.LowerName == name { ctx.Redirect(setting.AppSubUrl + ctx.Req.URL.Path) return } has, err := models.HasAccess(name, repoLink, models.WRITABLE) if err != nil { ctx.Handle(500, "HasAccess", err) return } else if has { ctx.Redirect(setting.AppSubUrl + ctx.Req.URL.Path) return } u, err := models.GetUserByName(name) if err != nil { if err == models.ErrUserNotExist { ctx.Flash.Error(ctx.Tr("form.user_not_exist")) ctx.Redirect(setting.AppSubUrl + ctx.Req.URL.Path) } else { ctx.Handle(500, "GetUserByName", err) } return } // Check if user is organization member. if ctx.Repo.Owner.IsOrganization() && ctx.Repo.Owner.IsOrgMember(u.Id) { ctx.Flash.Info(ctx.Tr("repo.settings.user_is_org_member")) ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration") return } if err = models.AddAccess(&models.Access{UserName: name, RepoName: repoLink, Mode: models.WRITABLE}); err != nil { ctx.Handle(500, "AddAccess", err) return } if setting.Service.EnableNotifyMail { if err = mailer.SendCollaboratorMail(ctx.Render, u, ctx.User, ctx.Repo.Repository); err != nil { ctx.Handle(500, "SendCollaboratorMail", err) return } } ctx.Flash.Success(ctx.Tr("repo.settings.add_collaborator_success")) ctx.Redirect(setting.AppSubUrl + ctx.Req.URL.Path) return } // Delete collaborator. remove := strings.ToLower(ctx.Query("remove")) if len(remove) > 0 && remove != ctx.Repo.Owner.LowerName { needDelete := true if ctx.User.IsOrganization() { // Check if user belongs to a team that has access to this repository. auth, err := models.GetHighestAuthorize(ctx.Repo.Owner.Id, ctx.User.Id, ctx.Repo.Repository.Id, 0) if err != nil { ctx.Handle(500, "GetHighestAuthorize", err) return } if auth > 0 { needDelete = false } } if needDelete { if err := models.DeleteAccess(&models.Access{UserName: remove, RepoName: repoLink}); err != nil { ctx.Handle(500, "DeleteAccess", err) return } } ctx.Flash.Success(ctx.Tr("repo.settings.remove_collaborator_success")) ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration") return } names, err := models.GetCollaboratorNames(repoLink) if err != nil { ctx.Handle(500, "GetCollaborators", err) return } collaborators := make([]*models.User, 0, len(names)) for _, name := range names { u, err := models.GetUserByName(name) if err != nil { ctx.Handle(500, "GetUserByName", err) return } // Does not show organization members. if ctx.Repo.Owner.IsOrganization() && ctx.Repo.Owner.IsOrgMember(u.Id) { continue } collaborators = append(collaborators, u) } ctx.Data["Collaborators"] = collaborators ctx.HTML(200, COLLABORATION) }
func runServ(k *cli.Context) { execDir, _ := base.ExecDir() newLogger(execDir) base.NewConfigContext() models.LoadModelsConfig() if models.UseSQLite3 { os.Chdir(execDir) } models.SetEngine() keys := strings.Split(os.Args[2], "-") if len(keys) != 2 { println("auth file format error") log.Error("auth file format error") return } keyId, err := strconv.ParseInt(keys[1], 10, 64) if err != nil { println("auth file format error") log.Error("auth file format error", err) return } user, err := models.GetUserByKeyId(keyId) if err != nil { println("You have no right to access") log.Error("SSH visit error: %v", err) return } cmd := os.Getenv("SSH_ORIGINAL_COMMAND") if cmd == "" { println("Hi", user.Name, "! You've successfully authenticated, but Gogs does not provide shell access.") return } verb, args := parseCmd(cmd) repoPath := strings.Trim(args, "'") rr := strings.SplitN(repoPath, "/", 2) if len(rr) != 2 { println("Unavilable repository", args) log.Error("Unavilable repository %v", args) return } repoUserName := rr[0] repoName := rr[1] if strings.HasSuffix(repoName, ".git") { repoName = repoName[:len(repoName)-4] } isWrite := In(verb, COMMANDS_WRITE) isRead := In(verb, COMMANDS_READONLY) repoUser, err := models.GetUserByName(repoUserName) if err != nil { fmt.Println("You have no right to access") log.Error("Get user failed", err) return } // access check switch { case isWrite: has, err := models.HasAccess(user.LowerName, path.Join(repoUserName, repoName), models.AU_WRITABLE) if err != nil { println("Inernel error:", err) log.Error(err.Error()) return } else if !has { println("You have no right to write this repository") log.Error("User %s has no right to write repository %s", user.Name, repoPath) return } case isRead: repo, err := models.GetRepositoryByName(repoUser.Id, repoName) if err != nil { println("Get repository error:", err) log.Error("Get repository error: " + err.Error()) return } if !repo.IsPrivate { break } has, err := models.HasAccess(user.Name, repoPath, models.AU_READABLE) if err != nil { println("Inernel error") log.Error(err.Error()) return } if !has { has, err = models.HasAccess(user.Name, repoPath, models.AU_WRITABLE) if err != nil { println("Inernel error") log.Error(err.Error()) return } } if !has { println("You have no right to access this repository") log.Error("You have no right to access this repository") return } default: println("Unknown command") log.Error("Unknown command") return } // for update use os.Setenv("userName", user.Name) os.Setenv("userId", strconv.Itoa(int(user.Id))) os.Setenv("repoName", repoName) gitcmd := exec.Command(verb, repoPath) gitcmd.Dir = base.RepoRootPath gitcmd.Stdout = os.Stdout gitcmd.Stdin = os.Stdin gitcmd.Stderr = os.Stderr if err = gitcmd.Run(); err != nil { println("execute command error:", err.Error()) log.Error("execute command error: " + err.Error()) return } }
func Http(ctx *middleware.Context, params martini.Params) { username := params["username"] reponame := 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 { ctx.Handle(500, "repo.GetUserByName", nil) return } repo, err := models.GetRepositoryByName(repoUser.Id, reponame) if err != nil { ctx.Handle(500, "repo.GetRepositoryByName", nil) return } // only public pull don't need auth isPublicPull := !repo.IsPrivate && isPull var askAuth = !isPublicPull || base.Service.RequireSignInView var authUser *models.User var authUsername, passwd string // check access if askAuth { baHead := ctx.Req.Header.Get("Authorization") if baHead == "" { // ask auth authRequired(ctx) return } auths := strings.Fields(baHead) // currently check basic auth // TODO: support digit auth if len(auths) != 2 || auths[0] != "Basic" { ctx.Handle(401, "no basic auth and digit auth", nil) return } authUsername, passwd, err = basicDecode(auths[1]) if err != nil { ctx.Handle(401, "no basic auth and digit auth", nil) return } authUser, err = models.GetUserByName(authUsername) if err != nil { ctx.Handle(401, "no basic auth and digit auth", nil) return } newUser := &models.User{Passwd: passwd, Salt: authUser.Salt} newUser.EncodePasswd() if authUser.Passwd != newUser.Passwd { ctx.Handle(401, "no basic auth and digit auth", nil) return } if !isPublicPull { var tp = models.AU_WRITABLE if isPull { tp = models.AU_READABLE } has, err := models.HasAccess(authUsername, username+"/"+reponame, tp) if err != nil { ctx.Handle(401, "no basic auth and digit auth", nil) return } else if !has { if tp == models.AU_READABLE { has, err = models.HasAccess(authUsername, username+"/"+reponame, models.AU_WRITABLE) 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 } } } } config := Config{base.RepoRootPath, "git", true, true, func(rpc string, input []byte) { if rpc == "receive-pack" { firstLine := bytes.IndexRune(input, '\000') if firstLine > -1 { fields := strings.Fields(string(input[:firstLine])) if len(fields) == 3 { oldCommitId := fields[0][4:] newCommitId := fields[1] refName := fields[2] models.Update(refName, oldCommitId, newCommitId, authUsername, username, reponame, authUser.Id) } } } }} handler := HttpBackend(&config) handler(ctx.ResponseWriter, ctx.Req) /* Webdav dir := models.RepoPath(username, reponame) prefix := path.Join("/", username, params["reponame"]) server := webdav.NewServer( dir, prefix, true) server.ServeHTTP(ctx.ResponseWriter, ctx.Req) */ }
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(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 ) // check access if askAuth { authSandstormId := ctx.Req.Header.Get("X-Sandstorm-User-Id") if authSandstormId == "" { authRequired(ctx) return } authUser, err = models.GetUserBySandstormID(authSandstormId) if err != nil { ctx.Handle(500, "UserSignIn error: %v", 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(500, "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(500, "HasAccess2", err) return } else if !has { ctx.HandleText(403, "User permission denied") return } } else { ctx.HandleText(403, "User permission denied") return } } if !isPull && repo.IsMirror { ctx.HandleText(403, "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] refName := fields[2] // FIXME: handle error. if err = models.PushUpdate(models.PushUpdateOptions{ RefName: refName, OldCommitID: oldCommitId, NewCommitID: newCommitId, PusherID: authUser.Id, PusherName: authUser.Name, RepoUserName: username, RepoName: reponame, }); err == nil { go models.HookQueue.Add(repo.ID) go models.AddTestPullRequestTask(repo.ID, strings.TrimPrefix(refName, "refs/heads/")) } } lastLine = lastLine + size } else { break } } } HTTPBackend(ctx, &Config{ RepoRootPath: setting.RepoRootPath, GitBinPath: "git", UploadPack: true, ReceivePack: true, OnSucceed: callback, })(ctx.Resp, ctx.Req.Request) runtime.GC() }