diff options
Diffstat (limited to 'models')
-rw-r--r-- | models/access.go | 26 | ||||
-rw-r--r-- | models/error.go | 52 | ||||
-rw-r--r-- | models/issue.go | 4 | ||||
-rw-r--r-- | models/login.go | 63 | ||||
-rw-r--r-- | models/org.go | 38 | ||||
-rw-r--r-- | models/repo.go | 90 | ||||
-rw-r--r-- | models/user.go | 31 |
7 files changed, 237 insertions, 67 deletions
diff --git a/models/access.go b/models/access.go index dd856afb..54d0f099 100644 --- a/models/access.go +++ b/models/access.go @@ -145,6 +145,25 @@ func (repo *Repository) refreshCollaboratorAccesses(e Engine, accessMap map[int6 for _, c := range collaborators { accessMap[c.Id] = ACCESS_MODE_WRITE } + + // Adds team members access. + if repo.Owner.IsOrganization() { + if err = repo.Owner.GetTeams(); err != nil { + return fmt.Errorf("GetTeams: %v", err) + } + for _, t := range repo.Owner.Teams { + if err = t.GetMembers(); err != nil { + return fmt.Errorf("GetMembers: %v", err) + } + for _, m := range t.Members { + if t.IsOwnerTeam() { + accessMap[m.Id] = ACCESS_MODE_OWNER + } else { + accessMap[m.Id] = maxAccessMode(accessMap[m.Id], t.Authorize) + } + } + } + } return nil } @@ -154,13 +173,12 @@ func (repo *Repository) refreshCollaboratorAccesses(e Engine, accessMap map[int6 func (repo *Repository) recalculateTeamAccesses(e Engine, ignTeamID int64) (err error) { accessMap := make(map[int64]AccessMode, 20) - if err = repo.refreshCollaboratorAccesses(e, accessMap); err != nil { - return fmt.Errorf("refreshCollaboratorAccesses: %v", err) - } - if err = repo.getOwner(e); err != nil { return err } + if err = repo.refreshCollaboratorAccesses(e, accessMap); err != nil { + return fmt.Errorf("refreshCollaboratorAccesses: %v", err) + } if repo.Owner.IsOrganization() { if err = repo.Owner.getTeams(e); err != nil { return err diff --git a/models/error.go b/models/error.go index a434b8d6..04f850de 100644 --- a/models/error.go +++ b/models/error.go @@ -8,6 +8,32 @@ import ( "fmt" ) +type ErrNameReserved struct { + Name string +} + +func IsErrNameReserved(err error) bool { + _, ok := err.(ErrNameReserved) + return ok +} + +func (err ErrNameReserved) Error() string { + return fmt.Sprintf("name is reserved: [name: %s]", err.Name) +} + +type ErrNamePatternNotAllowed struct { + Pattern string +} + +func IsErrNamePatternNotAllowed(err error) bool { + _, ok := err.(ErrNamePatternNotAllowed) + return ok +} + +func (err ErrNamePatternNotAllowed) Error() string { + return fmt.Sprintf("name pattern is not allowed: [pattern: %s]", err.Pattern) +} + // ____ ___ // | | \______ ___________ // | | / ___// __ \_ __ \ @@ -15,6 +41,32 @@ import ( // |______//____ >\___ >__| // \/ \/ +type ErrUserAlreadyExist struct { + Name string +} + +func IsErrUserAlreadyExist(err error) bool { + _, ok := err.(ErrUserAlreadyExist) + return ok +} + +func (err ErrUserAlreadyExist) Error() string { + return fmt.Sprintf("user already exists: [name: %s]", err.Name) +} + +type ErrEmailAlreadyUsed struct { + Email string +} + +func IsErrEmailAlreadyUsed(err error) bool { + _, ok := err.(ErrEmailAlreadyUsed) + return ok +} + +func (err ErrEmailAlreadyUsed) Error() string { + return fmt.Sprintf("e-mail has been used: [email: %s]", err.Email) +} + type ErrUserOwnRepos struct { UID int64 } diff --git a/models/issue.go b/models/issue.go index 2b80e576..60030447 100644 --- a/models/issue.go +++ b/models/issue.go @@ -282,7 +282,7 @@ type IssueUser struct { } // NewIssueUserPairs adds new issue-user pairs for new issue of repository. -func NewIssueUserPairs(repo *Repository, issueID, orgID, posterID, assigneeID int64) (err error) { +func NewIssueUserPairs(repo *Repository, issueID, orgID, posterID, assigneeID int64) error { users, err := repo.GetCollaborators() if err != nil { return err @@ -295,6 +295,7 @@ func NewIssueUserPairs(repo *Repository, issueID, orgID, posterID, assigneeID in isNeedAddPoster := true for _, u := range users { + iu.Id = 0 iu.Uid = u.Id iu.IsPoster = iu.Uid == posterID if isNeedAddPoster && iu.IsPoster { @@ -306,6 +307,7 @@ func NewIssueUserPairs(repo *Repository, issueID, orgID, posterID, assigneeID in } } if isNeedAddPoster { + iu.Id = 0 iu.Uid = posterID iu.IsPoster = true iu.IsAssigned = iu.Uid == assigneeID diff --git a/models/login.go b/models/login.go index 916e2731..10f782be 100644 --- a/models/login.go +++ b/models/login.go @@ -17,6 +17,7 @@ import ( "github.com/go-xorm/xorm" "github.com/gogits/gogs/modules/auth/ldap" + "github.com/gogits/gogs/modules/auth/pam" "github.com/gogits/gogs/modules/log" "github.com/gogits/gogs/modules/uuid" ) @@ -28,6 +29,7 @@ const ( PLAIN LDAP SMTP + PAM ) var ( @@ -39,12 +41,14 @@ var ( var LoginTypes = map[LoginType]string{ LDAP: "LDAP", SMTP: "SMTP", + PAM: "PAM", } // Ensure structs implemented interface. var ( _ core.Conversion = &LDAPConfig{} _ core.Conversion = &SMTPConfig{} + _ core.Conversion = &PAMConfig{} ) type LDAPConfig struct { @@ -74,6 +78,18 @@ func (cfg *SMTPConfig) ToDB() ([]byte, error) { return json.Marshal(cfg) } +type PAMConfig struct { + ServiceName string // pam service (e.g. system-auth) +} + +func (cfg *PAMConfig) FromDB(bs []byte) error { + return json.Unmarshal(bs, &cfg) +} + +func (cfg *PAMConfig) ToDB() ([]byte, error) { + return json.Marshal(cfg) +} + type LoginSource struct { Id int64 Type LoginType @@ -97,6 +113,10 @@ func (source *LoginSource) SMTP() *SMTPConfig { return source.Cfg.(*SMTPConfig) } +func (source *LoginSource) PAM() *PAMConfig { + return source.Cfg.(*PAMConfig) +} + func (source *LoginSource) BeforeSet(colName string, val xorm.Cell) { if colName == "type" { ty := (*val).(int64) @@ -105,6 +125,8 @@ func (source *LoginSource) BeforeSet(colName string, val xorm.Cell) { source.Cfg = new(LDAPConfig) case SMTP: source.Cfg = new(SMTPConfig) + case PAM: + source.Cfg = new(PAMConfig) } } } @@ -169,7 +191,7 @@ func UserSignIn(uname, passwd string) (*User, error) { // For plain login, user must exist to reach this line. // Now verify password. if u.LoginType == PLAIN { - if !u.ValidtePassword(passwd) { + if !u.ValidatePassword(passwd) { return nil, ErrUserNotExist } return u, nil @@ -197,6 +219,13 @@ func UserSignIn(uname, passwd string) (*User, error) { return u, nil } log.Warn("Fail to login(%s) by SMTP(%s): %v", uname, source.Name, err) + } else if source.Type == PAM { + u, err := LoginUserPAMSource(nil, uname, passwd, + source.Id, source.Cfg.(*PAMConfig), true) + if err == nil { + return u, nil + } + log.Warn("Fail to login(%s) by PAM(%s): %v", uname, source.Name, err) } } @@ -218,6 +247,8 @@ func UserSignIn(uname, passwd string) (*User, error) { return LoginUserLdapSource(u, u.LoginName, passwd, source.Id, source.Cfg.(*LDAPConfig), false) case SMTP: return LoginUserSMTPSource(u, u.LoginName, passwd, source.Id, source.Cfg.(*SMTPConfig), false) + case PAM: + return LoginUserPAMSource(u, u.LoginName, passwd, source.Id, source.Cfg.(*PAMConfig), false) } return nil, ErrUnsupportedLoginType } @@ -359,3 +390,33 @@ func LoginUserSMTPSource(u *User, name, passwd string, sourceId int64, cfg *SMTP err := CreateUser(u) return u, err } + +// Query if name/passwd can login against PAM +// Create a local user if success +// Return the same LoginUserPlain semantic +func LoginUserPAMSource(u *User, name, passwd string, sourceId int64, cfg *PAMConfig, autoRegister bool) (*User, error) { + if err := pam.PAMAuth(cfg.ServiceName, name, passwd); err != nil { + if strings.Contains(err.Error(), "Authentication failure") { + return nil, ErrUserNotExist + } + return nil, err + } + + if !autoRegister { + return u, nil + } + + // fake a local user creation + u = &User{ + LowerName: strings.ToLower(name), + Name: strings.ToLower(name), + LoginType: PAM, + LoginSource: sourceId, + LoginName: name, + IsActive: true, + Passwd: passwd, + Email: name, + } + err := CreateUser(u) + return u, err +} diff --git a/models/org.go b/models/org.go index 32f135cb..3caed30b 100644 --- a/models/org.go +++ b/models/org.go @@ -105,23 +105,23 @@ func IsOrgEmailUsed(email string) (bool, error) { } // CreateOrganization creates record of a new organization. -func CreateOrganization(org, owner *User) (*User, error) { - if !IsLegalName(org.Name) { - return nil, ErrUserNameIllegal +func CreateOrganization(org, owner *User) (err error) { + if err = IsUsableName(org.Name); err != nil { + return err } isExist, err := IsUserExist(0, org.Name) if err != nil { - return nil, err + return err } else if isExist { - return nil, ErrUserAlreadyExist + return ErrUserAlreadyExist{org.Name} } isExist, err = IsOrgEmailUsed(org.Email) if err != nil { - return nil, err + return err } else if isExist { - return nil, ErrEmailAlreadyUsed + return ErrEmailAlreadyUsed{org.Email} } org.LowerName = strings.ToLower(org.Name) @@ -135,11 +135,11 @@ func CreateOrganization(org, owner *User) (*User, error) { sess := x.NewSession() defer sessionRelease(sess) if err = sess.Begin(); err != nil { - return nil, err + return err } if _, err = sess.Insert(org); err != nil { - return nil, err + return fmt.Errorf("insert organization: %v", err) } // Create default owner team. @@ -151,7 +151,7 @@ func CreateOrganization(org, owner *User) (*User, error) { NumMembers: 1, } if _, err = sess.Insert(t); err != nil { - return nil, err + return fmt.Errorf("insert owner team: %v", err) } // Add initial creator to organization and owner team. @@ -162,7 +162,7 @@ func CreateOrganization(org, owner *User) (*User, error) { NumTeams: 1, } if _, err = sess.Insert(ou); err != nil { - return nil, err + return fmt.Errorf("insert org-user relation: %v", err) } tu := &TeamUser{ @@ -171,14 +171,14 @@ func CreateOrganization(org, owner *User) (*User, error) { TeamID: t.ID, } if _, err = sess.Insert(tu); err != nil { - return nil, err + return fmt.Errorf("insert team-user relation: %v", err) } if err = os.MkdirAll(UserPath(org.Name), os.ModePerm); err != nil { - return nil, err + return fmt.Errorf("create directory: %v", err) } - return org, sess.Commit() + return sess.Commit() } // GetOrgByName returns organization by given name. @@ -594,9 +594,9 @@ func (t *Team) RemoveRepository(repoID int64) error { // NewTeam creates a record of new team. // It's caller's responsibility to assign organization ID. -func NewTeam(t *Team) error { - if !IsLegalName(t.Name) { - return ErrTeamNameIllegal +func NewTeam(t *Team) (err error) { + if err = IsUsableName(t.Name); err != nil { + return err } has, err := x.Id(t.OrgID).Get(new(User)) @@ -670,8 +670,8 @@ func GetTeamById(teamId int64) (*Team, error) { // UpdateTeam updates information of team. func UpdateTeam(t *Team, authChanged bool) (err error) { - if !IsLegalName(t.Name) { - return ErrTeamNameIllegal + if err = IsUsableName(t.Name); err != nil { + return err } if len(t.Description) > 255 { diff --git a/models/repo.go b/models/repo.go index 91bb0d71..4ee5c382 100644 --- a/models/repo.go +++ b/models/repo.go @@ -37,10 +37,10 @@ const ( var ( ErrRepoAlreadyExist = errors.New("Repository already exist") ErrRepoFileNotExist = errors.New("Repository file does not exist") - ErrRepoNameIllegal = errors.New("Repository name contains illegal characters") ErrRepoFileNotLoaded = errors.New("Repository file not loaded") ErrMirrorNotExist = errors.New("Mirror does not exist") ErrInvalidReference = errors.New("Invalid reference specified") + ErrNameEmpty = errors.New("Name is empty") ) var ( @@ -223,12 +223,12 @@ func (repo *Repository) DescriptionHtml() template.HTML { } // IsRepositoryExist returns true if the repository with given name under user has already existed. -func IsRepositoryExist(u *User, repoName string) bool { - has, _ := x.Get(&Repository{ +func IsRepositoryExist(u *User, repoName string) (bool, error) { + has, err := x.Get(&Repository{ OwnerId: u.Id, LowerName: strings.ToLower(repoName), }) - return has && com.IsDir(RepoPath(u.Name, repoName)) + return has && com.IsDir(RepoPath(u.Name, repoName)), err } // CloneLink represents different types of clone URLs of repository. @@ -243,34 +243,42 @@ func (repo *Repository) CloneLink() (cl CloneLink, err error) { if err = repo.GetOwner(); err != nil { return cl, err } + if setting.SSHPort != 22 { - cl.SSH = fmt.Sprintf("ssh://%s@%s:%d/%s/%s.git", setting.RunUser, setting.Domain, setting.SSHPort, repo.Owner.LowerName, repo.LowerName) + cl.SSH = fmt.Sprintf("ssh://%s@%s:%d/%s/%s.git", setting.RunUser, setting.SSHDomain, setting.SSHPort, repo.Owner.LowerName, repo.LowerName) } else { - cl.SSH = fmt.Sprintf("%s@%s:%s/%s.git", setting.RunUser, setting.Domain, repo.Owner.LowerName, repo.LowerName) + cl.SSH = fmt.Sprintf("%s@%s:%s/%s.git", setting.RunUser, setting.SSHDomain, repo.Owner.LowerName, repo.LowerName) } cl.HTTPS = fmt.Sprintf("%s%s/%s.git", setting.AppUrl, repo.Owner.LowerName, repo.LowerName) return cl, nil } var ( - illegalEquals = []string{"debug", "raw", "install", "api", "avatar", "user", "org", "help", "stars", "issues", "pulls", "commits", "repo", "template", "admin", "new"} - illegalSuffixs = []string{".git", ".keys"} + reservedNames = []string{"debug", "raw", "install", "api", "avatar", "user", "org", "help", "stars", "issues", "pulls", "commits", "repo", "template", "admin", "new"} + reservedPatterns = []string{"*.git", "*.keys"} ) -// IsLegalName returns false if name contains illegal characters. -func IsLegalName(repoName string) bool { - repoName = strings.ToLower(repoName) - for _, char := range illegalEquals { - if repoName == char { - return false +// IsUsableName checks if name is reserved or pattern of name is not allowed. +func IsUsableName(name string) error { + name = strings.TrimSpace(strings.ToLower(name)) + if utf8.RuneCountInString(name) == 0 { + return ErrNameEmpty + } + + for i := range reservedNames { + if name == reservedNames[i] { + return ErrNameReserved{name} } } - for _, char := range illegalSuffixs { - if strings.HasSuffix(repoName, char) { - return false + + for _, pat := range reservedPatterns { + if pat[0] == '*' && strings.HasSuffix(name, pat[1:]) || + (pat[len(pat)-1] == '*' && strings.HasPrefix(name, pat[:len(pat)-1])) { + return ErrNamePatternNotAllowed{pat} } } - return true + + return nil } // Mirror represents a mirror information of repository. @@ -372,6 +380,15 @@ func MigrateRepository(u *User, name, desc string, private, mirror bool, url str return repo, fmt.Errorf("create update hook: %v", err) } + // Check if repository has master branch, if so set it to default branch. + gitRepo, err := git.OpenRepository(repoPath) + if err != nil { + return repo, fmt.Errorf("open git repository: %v", err) + } + if gitRepo.IsBranchExist("master") { + repo.DefaultBranch = "master" + } + return repo, UpdateRepository(repo, false) } @@ -504,11 +521,14 @@ func initRepository(e Engine, repoPath string, u *User, repo *Repository, initRe // CreateRepository creates a repository for given user or organization. func CreateRepository(u *User, name, desc, lang, license string, isPrivate, isMirror, initReadme bool) (_ *Repository, err error) { - if !IsLegalName(name) { - return nil, ErrRepoNameIllegal + if err = IsUsableName(name); err != nil { + return nil, err } - if IsRepositoryExist(u, name) { + has, err := IsRepositoryExist(u, name) + if err != nil { + return nil, fmt.Errorf("IsRepositoryExist: %v", err) + } else if has { return nil, ErrRepoAlreadyExist } @@ -619,7 +639,10 @@ func TransferOwnership(u *User, newOwnerName string, repo *Repository) error { } // Check if new owner has repository with same name. - if IsRepositoryExist(newOwner, repo.Name) { + has, err := IsRepositoryExist(newOwner, repo.Name) + if err != nil { + return fmt.Errorf("IsRepositoryExist: %v", err) + } else if has { return ErrRepoAlreadyExist } @@ -727,16 +750,22 @@ func TransferOwnership(u *User, newOwnerName string, repo *Repository) error { } // ChangeRepositoryName changes all corresponding setting from old repository name to new one. -func ChangeRepositoryName(userName, oldRepoName, newRepoName string) (err error) { - userName = strings.ToLower(userName) +func ChangeRepositoryName(u *User, oldRepoName, newRepoName string) (err error) { oldRepoName = strings.ToLower(oldRepoName) newRepoName = strings.ToLower(newRepoName) - if !IsLegalName(newRepoName) { - return ErrRepoNameIllegal + if err = IsUsableName(newRepoName); err != nil { + return err + } + + has, err := IsRepositoryExist(u, newRepoName) + if err != nil { + return fmt.Errorf("IsRepositoryExist: %v", err) + } else if has { + return ErrRepoAlreadyExist } // Change repository directory name. - return os.Rename(RepoPath(userName, oldRepoName), RepoPath(userName, newRepoName)) + return os.Rename(RepoPath(u.LowerName, oldRepoName), RepoPath(u.LowerName, newRepoName)) } func updateRepository(e Engine, repo *Repository, visibilityChanged bool) (err error) { @@ -1029,7 +1058,7 @@ func MirrorUpdate() { repoPath := filepath.Join(setting.RepoRootPath, m.RepoName+".git") if _, stderr, err := process.ExecDir(10*time.Minute, repoPath, fmt.Sprintf("MirrorUpdate: %s", repoPath), - "git", "remote", "update"); err != nil { + "git", "remote", "update", "--prune"); err != nil { desc := fmt.Sprintf("Fail to update mirror repository(%s): %s", repoPath, stderr) log.Error(4, desc) if err = CreateRepositoryNotice(desc); err != nil { @@ -1340,7 +1369,10 @@ func IsStaring(uid, repoId int64) bool { // \/ \/ func ForkRepository(u *User, oldRepo *Repository, name, desc string) (_ *Repository, err error) { - if IsRepositoryExist(u, name) { + has, err := IsRepositoryExist(u, name) + if err != nil { + return nil, fmt.Errorf("IsRepositoryExist: %v", err) + } else if has { return nil, ErrRepoAlreadyExist } diff --git a/models/user.go b/models/user.go index dcfd0dc5..e239ea17 100644 --- a/models/user.go +++ b/models/user.go @@ -36,10 +36,8 @@ const ( ) var ( - ErrUserAlreadyExist = errors.New("User already exist") ErrUserNotExist = errors.New("User does not exist") ErrUserNotKeyOwner = errors.New("User does not the owner of public key") - ErrEmailAlreadyUsed = errors.New("E-mail already used") ErrEmailNotExist = errors.New("E-mail does not exist") ErrEmailNotActivated = errors.New("E-mail address has not been activated") ErrUserNameIllegal = errors.New("User name contains illegal characters") @@ -145,8 +143,8 @@ func (u *User) EncodePasswd() { u.Passwd = fmt.Sprintf("%x", newPasswd) } -// ValidtePassword checks if given password matches the one belongs to the user. -func (u *User) ValidtePassword(passwd string) bool { +// ValidatePassword checks if given password matches the one belongs to the user. +func (u *User) ValidatePassword(passwd string) bool { newUser := &User{Passwd: passwd, Salt: u.Salt} newUser.EncodePasswd() return u.Passwd == newUser.Passwd @@ -273,23 +271,23 @@ func GetUserSalt() string { } // CreateUser creates record of a new user. -func CreateUser(u *User) error { - if !IsLegalName(u.Name) { - return ErrUserNameIllegal +func CreateUser(u *User) (err error) { + if err = IsUsableName(u.Name); err != nil { + return err } isExist, err := IsUserExist(0, u.Name) if err != nil { return err } else if isExist { - return ErrUserAlreadyExist + return ErrUserAlreadyExist{u.Name} } isExist, err = IsEmailUsed(u.Email) if err != nil { return err } else if isExist { - return ErrEmailAlreadyUsed + return ErrEmailAlreadyUsed{u.Email} } u.LowerName = strings.ToLower(u.Name) @@ -392,8 +390,15 @@ func VerifyActiveEmailCode(code, email string) *EmailAddress { // ChangeUserName changes all corresponding setting from old user name to new one. func ChangeUserName(u *User, newUserName string) (err error) { - if !IsLegalName(newUserName) { - return ErrUserNameIllegal + if err = IsUsableName(newUserName); err != nil { + return err + } + + isExist, err := IsUserExist(0, newUserName) + if err != nil { + return err + } else if isExist { + return ErrUserAlreadyExist{newUserName} } return os.Rename(UserPath(u.LowerName), UserPath(newUserName)) @@ -405,7 +410,7 @@ func UpdateUser(u *User) error { if err != nil { return err } else if has { - return ErrEmailAlreadyUsed + return ErrEmailAlreadyUsed{u.Email} } u.LowerName = strings.ToLower(u.Name) @@ -641,7 +646,7 @@ func AddEmailAddress(email *EmailAddress) error { if err != nil { return err } else if used { - return ErrEmailAlreadyUsed + return ErrEmailAlreadyUsed{email.Email} } _, err = x.Insert(email) |