mirror of https://github.com/gogs/gogs.git
139 lines
4.0 KiB
Go
139 lines
4.0 KiB
Go
// 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 db
|
|
|
|
import (
|
|
"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 UsersStore
|
|
|
|
type 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
|
|
}
|