Commit c1a5e402 authored by Mo Firouz's avatar Mo Firouz Committed by Andrei Mihu
Browse files

Fix various race conditions. Lowercase incoming usernames. (#151)

parent 88867911
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import (

	_ "github.com/lib/pq"
	"github.com/golang/protobuf/jsonpb"
	"math/rand"
)

var (
@@ -43,6 +44,8 @@ func main() {
	semver := fmt.Sprintf("%s+%s", version, commitID)
	// Always set default timeout on HTTP client.
	http.DefaultClient.Timeout = 1500 * time.Millisecond
	// Initialize the global random obj with customs seed.
	rand.Seed(time.Now().UnixNano())

	cmdLogger := server.NewJSONLogger(os.Stdout, true)

perf/nakama2.jmx

0 → 100644
+41 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="3.2" jmeter="3.3 r1808647">
  <hashTree>
    <ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="View Results Tree" enabled="true">
      <boolProp name="ResultCollector.error_logging">false</boolProp>
      <objProp>
        <name>saveConfig</name>
        <value class="SampleSaveConfiguration">
          <time>true</time>
          <latency>true</latency>
          <timestamp>true</timestamp>
          <success>true</success>
          <label>true</label>
          <code>true</code>
          <message>true</message>
          <threadName>true</threadName>
          <dataType>true</dataType>
          <encoding>false</encoding>
          <assertions>true</assertions>
          <subresults>true</subresults>
          <responseData>false</responseData>
          <samplerData>false</samplerData>
          <xml>false</xml>
          <fieldNames>true</fieldNames>
          <responseHeaders>false</responseHeaders>
          <requestHeaders>false</requestHeaders>
          <responseDataOnError>false</responseDataOnError>
          <saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
          <assertionsResultsToSave>0</assertionsResultsToSave>
          <bytes>true</bytes>
          <sentBytes>true</sentBytes>
          <threadCounts>true</threadCounts>
          <idleTime>true</idleTime>
          <connectTime>true</connectTime>
        </value>
      </objProp>
      <stringProp name="filename"></stringProp>
    </ResultCollector>
    <hashTree/>
  </hashTree>
</jmeterTestPlan>
+0 −4
Original line number Diff line number Diff line
@@ -19,11 +19,9 @@ import (
	"database/sql"
	"encoding/base64"
	"fmt"
	"math/rand"
	"net"
	"net/http"
	"strings"
	"time"

	"github.com/dgrijalva/jwt-go"
	"github.com/golang/protobuf/jsonpb"
@@ -53,7 +51,6 @@ type ApiServer struct {
	db                *sql.DB
	config            Config
	runtimePool       *RuntimePool
	random            *rand.Rand
	grpcServer        *grpc.Server
	grpcGatewayServer *http.Server
}
@@ -69,7 +66,6 @@ func StartApiServer(logger *zap.Logger, db *sql.DB, config Config, registry *Ses
		db:          db,
		config:      config,
		runtimePool: runtimePool,
		random:      rand.New(rand.NewSource(time.Now().UnixNano())),
		grpcServer:  grpcServer,
	}

+8 −5
Original line number Diff line number Diff line
@@ -41,8 +41,9 @@ func (s *ApiServer) AuthenticateCustom(ctx context.Context, in *api.Authenticate
	}

	username := in.Username
	username = strings.ToLower(username)
	if username == "" {
		username = generateUsername(s.random)
		username = generateUsername()
	} else if invalidCharsRegex.MatchString(username) {
		return nil, status.Error(codes.InvalidArgument, "Username invalid, no spaces or control characters allowed.")
	} else if len(username) > 128 {
@@ -70,8 +71,9 @@ func (s *ApiServer) AuthenticateDevice(ctx context.Context, in *api.Authenticate
	}

	username := in.Username
	username = strings.ToLower(username)
	if username == "" {
		username = generateUsername(s.random)
		username = generateUsername()
	} else if invalidCharsRegex.MatchString(username) {
		return nil, status.Error(codes.InvalidArgument, "Username invalid, no spaces or control characters allowed.")
	} else if len(username) > 128 {
@@ -106,8 +108,9 @@ func (s *ApiServer) AuthenticateEmail(ctx context.Context, in *api.AuthenticateE
	cleanEmail := strings.ToLower(email.Email)

	username := in.Username
	username = strings.ToLower(username)
	if username == "" {
		username = generateUsername(s.random)
		username = generateUsername()
	} else if invalidCharsRegex.MatchString(username) {
		return nil, status.Error(codes.InvalidArgument, "Username invalid , no spaces or control characters allowed.")
	} else if len(username) > 128 {
@@ -156,11 +159,11 @@ func generateTokenWithExpiry(config Config, userID, username string, exp int64)
	return signedToken
}

func generateUsername(random *rand.Rand) string {
func generateUsername() string {
	const usernameAlphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
	b := make([]byte, 10)
	for i := range b {
		b[i] = usernameAlphabet[random.Intn(len(usernameAlphabet))]
		b[i] = usernameAlphabet[rand.Intn(len(usernameAlphabet))]
	}
	return string(b)
}
+7 −7
Original line number Diff line number Diff line
@@ -37,13 +37,6 @@ func (s *ApiServer) RpcFunc(ctx context.Context, in *api.Rpc) (*api.Rpc, error)
		return nil, status.Error(codes.NotFound, "RPC function not found")
	}

	runtime := s.runtimePool.Get()
	lf := runtime.GetRuntimeCallback(RPC, id)
	if lf == nil {
		s.runtimePool.Put(runtime)
		return nil, status.Error(codes.NotFound, "RPC function not found")
	}

	uid := ""
	username := ""
	expiry := int64(0)
@@ -57,6 +50,13 @@ func (s *ApiServer) RpcFunc(ctx context.Context, in *api.Rpc) (*api.Rpc, error)
		expiry = e.(int64)
	}

	runtime := s.runtimePool.Get()
	lf := runtime.GetRuntimeCallback(RPC, id)
	if lf == nil {
		s.runtimePool.Put(runtime)
		return nil, status.Error(codes.NotFound, "RPC function not found")
	}

	result, fnErr := runtime.InvokeFunctionRPC(lf, uid, username, expiry, "", in.Payload.Value)
	s.runtimePool.Put(runtime)
	if fnErr != nil {
Loading