Commit 0235f973 authored by Andrei Mihu's avatar Andrei Mihu
Browse files

Update config elements and parsing.

parent df009620
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -248,7 +248,7 @@ func NewDatabaseConfig() *DatabaseConfig {
		Addresses:         []string{"root@localhost:26257"},
		ConnMaxLifetimeMs: 0,
		MaxOpenConns:      0,
		MaxIdleConns:      2,
		MaxIdleConns:      100,
	}
}

+48 −52
Original line number Diff line number Diff line
@@ -19,80 +19,76 @@ import (
	"strings"
	"time"

	"encoding/json"
	"github.com/golang/protobuf/ptypes/timestamp"
	"github.com/heroiclabs/nakama/api"
	"github.com/heroiclabs/nakama/social"
	"github.com/lib/pq"
	"github.com/satori/go.uuid"
	"go.uber.org/zap"
	"golang.org/x/crypto/bcrypt"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"github.com/heroiclabs/nakama/social"
	"strconv"
	"github.com/heroiclabs/nakama/api"
	"github.com/golang/protobuf/ptypes/timestamp"
	"encoding/json"
)

func AuthenticateCustom(logger *zap.Logger, db *sql.DB, customID, username string, create bool) (string, string, error) {
	if create {
		// Use existing user account if found, otherwise create a new user account.
		userID := uuid.NewV4().String()
		ts := time.Now().UTC().Unix()
		// NOTE: This query relies on the `custom_id` conflict triggering before the `users_username_key`
		// constraint violation to ensure we fall to the RETURNING case and ignore the new username for
		// existing user accounts. The DO UPDATE SET is to trick the DB into having the data we need to return.
		query := `
INSERT INTO users (id, username, custom_id, create_time, update_time)
VALUES ($1, $2, $3, $4, $4)
ON CONFLICT (custom_id) DO UPDATE SET custom_id = $3
RETURNING id, username, disable_time`
	found := true

	// Look for an existing account.
	query := "SELECT id, username, disable_time FROM users WHERE custom_id = $1"
	var dbUserID string
	var dbUsername string
	var dbDisableTime int64
		err := db.QueryRow(query, userID, username, customID, ts).Scan(&dbUserID, &dbUsername, &dbDisableTime)
	err := db.QueryRow(query, customID).Scan(&dbUserID, &dbUsername, &dbDisableTime)
	if err != nil {
			if e, ok := err.(*pq.Error); ok && e.Code == dbErrorUniqueViolation && strings.Contains(e.Message, "users_username_key") {
				// Username is already in use by a different account.
				return "", "", status.Error(codes.AlreadyExists, "Username is already in use.")
		if err == sql.ErrNoRows {
			found = false
		} else {
			logger.Error("Cannot find user with custom ID.", zap.Error(err), zap.String("customID", customID), zap.String("username", username), zap.Bool("create", create))
			return "", "", status.Error(codes.Internal, "Error finding user account.")
		}
			logger.Error("Cannot find or create user with custom ID.", zap.Error(err), zap.String("customID", customID), zap.String("username", username), zap.Bool("create", create))
			return "", "", status.Error(codes.Internal, "Error finding or creating user account.")
	}

	// Existing account found.
	if found {
		// Check if it's disabled.
		if dbDisableTime != 0 {
			logger.Debug("User account is disabled.", zap.String("customID", customID), zap.String("username", username), zap.Bool("create", create))
			return "", "", status.Error(codes.Unauthenticated, "Error finding or creating user account.")
		}

		return dbUserID, dbUsername, nil
	} else {
		// Do not create a new user account.
		query := `
SELECT id, username, disable_time
FROM users
WHERE custom_id = $1`
	}

		var dbUserID string
		var dbUsername string
		var dbDisableTime int64
		err := db.QueryRow(query, customID).Scan(&dbUserID, &dbUsername, &dbDisableTime)
		if err != nil {
			if err == sql.ErrNoRows {
				// No user account found.
	if !create {
		// No user account found, and creation is not allowed.
		return "", "", status.Error(codes.NotFound, "User account not found.")
			} else {
				logger.Error("Cannot find user with custom ID.", zap.Error(err), zap.String("customID", customID), zap.String("username", username), zap.Bool("create", create))
				return "", "", status.Error(codes.Internal, "Error finding user account.")
			}
	}

		if dbDisableTime != 0 {
			logger.Debug("User account is disabled.", zap.String("customID", customID), zap.String("username", username), zap.Bool("create", create))
			return "", "", status.Error(codes.Unauthenticated, "Error finding or creating user account.")
	// Create a new account.
	userID := uuid.NewV4().String()
	query = "INSERT INTO users (id, username, custom_id, create_time, update_time) VALUES ($1, $2, $3, $4, $4)"
	result, err := db.Exec(query, userID, username, customID, time.Now().UTC().Unix())
	if err != nil {
		if e, ok := err.(*pq.Error); ok && e.Code == dbErrorUniqueViolation {
			if strings.Contains(e.Message, "users_username_key") {
				// Username is already in use by a different account.
				return "", "", status.Error(codes.AlreadyExists, "Username is already in use.")
			} else if strings.Contains(e.Message, "users_custom_id_key") {
				// A concurrent write has inserted this custom ID.
				return "", "", status.Error(codes.Internal, "Error finding or creating user account.")
			}
		}
		logger.Error("Cannot find or create user with custom ID.", zap.Error(err), zap.String("customID", customID), zap.String("username", username), zap.Bool("create", create))
		return "", "", status.Error(codes.Internal, "Error finding or creating user account.")
	}

		return dbUserID, dbUsername, nil
	if rowsAffectedCount, _ := result.RowsAffected(); rowsAffectedCount != 1 {
		return "", "", status.Error(codes.Internal, "Error finding or creating user account.")
	}

	return userID, username, nil
}

func AuthenticateDevice(logger *zap.Logger, db *sql.DB, deviceID, username string, create bool) (string, string, error) {