| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 | // Copyright 2020 The Gogs Authors. All rights reserved.// Use of this source code is governed by a MIT-style// license that can be found in the LICENSE file.package dbimport (	"fmt"	"strings"	"github.com/jinzhu/gorm"	"github.com/pkg/errors"	"gogs.io/gogs/internal/errutil")// UsersStore is the persistent interface for users.//// NOTE: All methods are sorted in alphabetical order.type UsersStore interface {	// Authenticate validates username and password via given login source ID.	// It returns ErrUserNotExist when the user was not found.	//	// When the "loginSourceID" is negative, it aborts the process and returns	// ErrUserNotExist if the user was not found in the database.	//	// When the "loginSourceID" is non-negative, it returns ErrLoginSourceMismatch	// if the user has different login source ID than the "loginSourceID".	//	// When the "loginSourceID" is positive, it tries to authenticate via given	// login source and creates a new user when not yet exists in the database.	Authenticate(username, password string, loginSourceID int64) (*User, error)	// GetByID returns the user with given ID. It returns ErrUserNotExist when not found.	GetByID(id int64) (*User, error)	// GetByUsername returns the user with given username. It returns ErrUserNotExist	// when not found.	GetByUsername(username string) (*User, error)}var Users UsersStoretype users struct {	*gorm.DB}type ErrLoginSourceMismatch struct {	args errutil.Args}func (err ErrLoginSourceMismatch) Error() string {	return fmt.Sprintf("login source mismatch: %v", err.args)}func (db *users) Authenticate(username, password string, loginSourceID int64) (*User, error) {	username = strings.ToLower(username)	var query *gorm.DB	if strings.Contains(username, "@") {		query = db.Where("email = ?", username)	} else {		query = db.Where("lower_name = ?", username)	}	user := new(User)	err := query.First(user).Error	if err != nil && err != gorm.ErrRecordNotFound {		return nil, errors.Wrap(err, "get user")	}	// User found in the database	if err == nil {		// Note: This check is unnecessary but to reduce user confusion at login page		// and make it more consistent from user's perspective.		if loginSourceID >= 0 && user.LoginSource != loginSourceID {			return nil, ErrLoginSourceMismatch{args: errutil.Args{"expect": loginSourceID, "actual": user.LoginSource}}		}		// Validate password hash fetched from database for local accounts.		if user.LoginType == LoginNotype || user.LoginType == LoginPlain {			if user.ValidatePassword(password) {				return user, nil			}			return nil, ErrUserNotExist{args: map[string]interface{}{"userID": user.ID, "name": user.Name}}		}		source, err := LoginSources.GetByID(user.LoginSource)		if err != nil {			return nil, errors.Wrap(err, "get login source")		}		_, err = authenticateViaLoginSource(source, username, password, false)		if err != nil {			return nil, errors.Wrap(err, "authenticate via login source")		}		return user, nil	}	// Non-local login source is always greater than 0.	if loginSourceID <= 0 {		return nil, ErrUserNotExist{args: map[string]interface{}{"name": username}}	}	source, err := LoginSources.GetByID(loginSourceID)	if err != nil {		return nil, errors.Wrap(err, "get login source")	}	user, err = authenticateViaLoginSource(source, username, password, true)	if err != nil {		return nil, errors.Wrap(err, "authenticate via login source")	}	return user, nil}func (db *users) GetByID(id int64) (*User, error) {	user := new(User)	err := db.Where("id = ?", id).First(user).Error	if err != nil {		if gorm.IsRecordNotFoundError(err) {			return nil, ErrUserNotExist{args: map[string]interface{}{"userID": id}}		}		return nil, err	}	return user, nil}func (db *users) GetByUsername(username string) (*User, error) {	user := new(User)	err := db.Where("lower_name = ?", strings.ToLower(username)).First(user).Error	if err != nil {		if gorm.IsRecordNotFoundError(err) {			return nil, ErrUserNotExist{args: map[string]interface{}{"name": username}}		}		return nil, err	}	return user, nil}
 |