Loading main.go +5 −2 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import ( "github.com/golang/protobuf/jsonpb" "github.com/heroiclabs/nakama/migrate" "github.com/heroiclabs/nakama/server" "github.com/heroiclabs/nakama/social" _ "github.com/lib/pq" "go.uber.org/zap" ) Loading Loading @@ -83,16 +84,18 @@ func main() { // Check migration status and log if the schema has diverged. migrate.StartupCheck(multiLogger, db) socialClient := social.NewClient(5 * time.Second) // Start up server components. registry := server.NewSessionRegistry() tracker := server.StartLocalTracker(jsonLogger, registry, jsonpbMarshaler, config.GetName()) router := server.NewLocalMessageRouter(registry, tracker, jsonpbMarshaler) runtimePool, err := server.NewRuntimePool(jsonLogger, multiLogger, db, config, registry, tracker, router) runtimePool, err := server.NewRuntimePool(jsonLogger, multiLogger, db, config, socialClient, registry, tracker, router) if err != nil { multiLogger.Fatal("Failed initializing runtime modules", zap.Error(err)) } pipeline := server.NewPipeline(config, db, registry, tracker, router, runtimePool) apiServer := server.StartApiServer(jsonLogger, db, jsonpbMarshaler, jsonpbUnmarshaler, config, registry, tracker, router, pipeline, runtimePool) apiServer := server.StartApiServer(jsonLogger, db, jsonpbMarshaler, jsonpbUnmarshaler, config, socialClient, registry, tracker, router, pipeline, runtimePool) // Respect OS stop signals. c := make(chan os.Signal, 2) Loading server/api.go +11 −8 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import ( _ "google.golang.org/grpc/encoding/gzip" // enable gzip compression on server for grpc "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" "github.com/heroiclabs/nakama/social" ) // Keys used for storing/retrieving user information in the context of a request after authentication. Loading @@ -53,11 +54,12 @@ type ApiServer struct { runtimePool *RuntimePool tracker Tracker router MessageRouter socialClient *social.Client grpcServer *grpc.Server grpcGatewayServer *http.Server } func StartApiServer(logger *zap.Logger, db *sql.DB, jsonpbMarshaler *jsonpb.Marshaler, jsonpbUnmarshaler *jsonpb.Unmarshaler, config Config, registry *SessionRegistry, tracker Tracker, router MessageRouter, pipeline *pipeline, runtimePool *RuntimePool) *ApiServer { func StartApiServer(logger *zap.Logger, db *sql.DB, jsonpbMarshaler *jsonpb.Marshaler, jsonpbUnmarshaler *jsonpb.Unmarshaler, config Config, socialClient *social.Client, registry *SessionRegistry, tracker Tracker, router MessageRouter, pipeline *pipeline, runtimePool *RuntimePool) *ApiServer { grpcServer := grpc.NewServer( grpc.StatsHandler(ocgrpc.NewServerStatsHandler()), grpc.UnaryInterceptor(SecurityInterceptorFunc(logger, config)), Loading @@ -70,6 +72,7 @@ func StartApiServer(logger *zap.Logger, db *sql.DB, jsonpbMarshaler *jsonpb.Mars runtimePool: runtimePool, tracker: tracker, router: router, socialClient: socialClient, grpcServer: grpcServer, } Loading server/api_account.go +1 −1 Original line number Diff line number Diff line Loading @@ -27,7 +27,7 @@ import ( func (s *ApiServer) GetAccount(ctx context.Context, in *empty.Empty) (*api.Account, error) { userID := ctx.Value(ctxUserIDKey{}).(uuid.UUID) user, err := GetAccount(s.db, s.logger, userID) user, err := GetAccount(s.db, s.logger, s.tracker, userID) if err != nil { return nil, status.Error(codes.Internal, "Error retrieving user account.") } Loading server/api_authenticate.go +115 −5 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import ( "github.com/dgrijalva/jwt-go" "github.com/heroiclabs/nakama/api" "github.com/satori/go.uuid" "golang.org/x/net/context" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" Loading Loading @@ -130,19 +131,128 @@ func (s *ApiServer) AuthenticateEmail(ctx context.Context, in *api.AuthenticateE } func (s *ApiServer) AuthenticateFacebook(ctx context.Context, in *api.AuthenticateFacebookRequest) (*api.Session, error) { return nil, nil if in.Account == nil || in.Account.Token == "" { return nil, status.Error(codes.InvalidArgument, "Facebook access token is required.") } username := in.Username username = strings.ToLower(username) if username == "" { 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 { return nil, status.Error(codes.InvalidArgument, "Username invalid, must be 1-128 bytes.") } create := in.Create == nil || in.Create.Value dbUserID, dbUsername, err := AuthenticateFacebook(s.logger, s.db, s.socialClient, in.Account.Token, username, create) if err != nil { return nil, err } // Import friends if requested. if in.Import == nil || in.Import.Value { importFacebookFriends(s.logger, s.db, s.socialClient, uuid.FromStringOrNil(dbUserID), dbUsername, in.Account.Token) } token := generateToken(s.config, dbUserID, dbUsername) return &api.Session{Token: token}, nil } func (s *ApiServer) AuthenticateGameCenter(ctx context.Context, in *api.AuthenticateGameCenterRequest) (*api.Session, error) { return nil, nil if in.Account == nil { return nil, status.Error(codes.InvalidArgument, "GameCenter access credentials are required.") } else if in.Account.BundleId == "" { return nil, status.Error(codes.InvalidArgument, "GameCenter bundle ID is required.") } else if in.Account.PlayerId == "" { return nil, status.Error(codes.InvalidArgument, "GameCenter player ID is required.") } else if in.Account.PublicKeyUrl == "" { return nil, status.Error(codes.InvalidArgument, "GameCenter public key URL is required.") } else if in.Account.Salt == "" { return nil, status.Error(codes.InvalidArgument, "GameCenter salt is required.") } else if in.Account.Signature == "" { return nil, status.Error(codes.InvalidArgument, "GameCenter signature is required.") } else if in.Account.TimestampSeconds == 0 { return nil, status.Error(codes.InvalidArgument, "GameCenter timestamp is required.") } username := in.Username username = strings.ToLower(username) if username == "" { 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 { return nil, status.Error(codes.InvalidArgument, "Username invalid, must be 1-128 bytes.") } create := in.Create == nil || in.Create.Value dbUserID, dbUsername, err := AuthenticateGameCenter(s.logger, s.db, s.socialClient, in.Account.PlayerId, in.Account.BundleId, in.Account.TimestampSeconds, in.Account.Salt, in.Account.Signature, in.Account.PublicKeyUrl, username, create) if err != nil { return nil, err } token := generateToken(s.config, dbUserID, dbUsername) return &api.Session{Token: token}, nil } func (s *ApiServer) AuthenticateGoogle(ctx context.Context, in *api.AuthenticateGoogleRequest) (*api.Session, error) { return nil, nil if in.Account == nil || in.Account.Token == "" { return nil, status.Error(codes.InvalidArgument, "Google access token is required.") } username := in.Username username = strings.ToLower(username) if username == "" { 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 { return nil, status.Error(codes.InvalidArgument, "Username invalid, must be 1-128 bytes.") } create := in.Create == nil || in.Create.Value dbUserID, dbUsername, err := AuthenticateGoogle(s.logger, s.db, s.socialClient, in.Account.Token, username, create) if err != nil { return nil, err } token := generateToken(s.config, dbUserID, dbUsername) return &api.Session{Token: token}, nil } func (s *ApiServer) AuthenticateSteam(ctx context.Context, in *api.AuthenticateSteamRequest) (*api.Session, error) { return nil, nil if s.config.GetSocial().Steam.PublisherKey == "" || s.config.GetSocial().Steam.AppID == 0 { return nil, status.Error(codes.FailedPrecondition, "Steam authentication is not configured.") } if in.Account == nil || in.Account.Token == "" { return nil, status.Error(codes.InvalidArgument, "Steam access token is required.") } username := in.Username username = strings.ToLower(username) if username == "" { 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 { return nil, status.Error(codes.InvalidArgument, "Username invalid, must be 1-128 bytes.") } create := in.Create == nil || in.Create.Value dbUserID, dbUsername, err := AuthenticateSteam(s.logger, s.db, s.socialClient, s.config.GetSocial().Steam.AppID, s.config.GetSocial().Steam.PublisherKey, in.Account.Token, username, create) if err != nil { return nil, err } token := generateToken(s.config, dbUserID, dbUsername) return &api.Session{Token: token}, nil } func generateToken(config Config, userID, username string) string { Loading server/api_friend.go +1 −1 Original line number Diff line number Diff line Loading @@ -27,7 +27,7 @@ import ( func (s *ApiServer) ListFriends(ctx context.Context, in *empty.Empty) (*api.Friends, error) { userID := ctx.Value(ctxUserIDKey{}).(uuid.UUID) friends, err := GetFriends(s.logger, s.db, userID) friends, err := GetFriends(s.logger, s.db, s.tracker, userID) if err != nil { return nil, status.Error(codes.Internal, "Error while trying to list friends.") } Loading Loading
main.go +5 −2 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import ( "github.com/golang/protobuf/jsonpb" "github.com/heroiclabs/nakama/migrate" "github.com/heroiclabs/nakama/server" "github.com/heroiclabs/nakama/social" _ "github.com/lib/pq" "go.uber.org/zap" ) Loading Loading @@ -83,16 +84,18 @@ func main() { // Check migration status and log if the schema has diverged. migrate.StartupCheck(multiLogger, db) socialClient := social.NewClient(5 * time.Second) // Start up server components. registry := server.NewSessionRegistry() tracker := server.StartLocalTracker(jsonLogger, registry, jsonpbMarshaler, config.GetName()) router := server.NewLocalMessageRouter(registry, tracker, jsonpbMarshaler) runtimePool, err := server.NewRuntimePool(jsonLogger, multiLogger, db, config, registry, tracker, router) runtimePool, err := server.NewRuntimePool(jsonLogger, multiLogger, db, config, socialClient, registry, tracker, router) if err != nil { multiLogger.Fatal("Failed initializing runtime modules", zap.Error(err)) } pipeline := server.NewPipeline(config, db, registry, tracker, router, runtimePool) apiServer := server.StartApiServer(jsonLogger, db, jsonpbMarshaler, jsonpbUnmarshaler, config, registry, tracker, router, pipeline, runtimePool) apiServer := server.StartApiServer(jsonLogger, db, jsonpbMarshaler, jsonpbUnmarshaler, config, socialClient, registry, tracker, router, pipeline, runtimePool) // Respect OS stop signals. c := make(chan os.Signal, 2) Loading
server/api.go +11 −8 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import ( _ "google.golang.org/grpc/encoding/gzip" // enable gzip compression on server for grpc "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" "github.com/heroiclabs/nakama/social" ) // Keys used for storing/retrieving user information in the context of a request after authentication. Loading @@ -53,11 +54,12 @@ type ApiServer struct { runtimePool *RuntimePool tracker Tracker router MessageRouter socialClient *social.Client grpcServer *grpc.Server grpcGatewayServer *http.Server } func StartApiServer(logger *zap.Logger, db *sql.DB, jsonpbMarshaler *jsonpb.Marshaler, jsonpbUnmarshaler *jsonpb.Unmarshaler, config Config, registry *SessionRegistry, tracker Tracker, router MessageRouter, pipeline *pipeline, runtimePool *RuntimePool) *ApiServer { func StartApiServer(logger *zap.Logger, db *sql.DB, jsonpbMarshaler *jsonpb.Marshaler, jsonpbUnmarshaler *jsonpb.Unmarshaler, config Config, socialClient *social.Client, registry *SessionRegistry, tracker Tracker, router MessageRouter, pipeline *pipeline, runtimePool *RuntimePool) *ApiServer { grpcServer := grpc.NewServer( grpc.StatsHandler(ocgrpc.NewServerStatsHandler()), grpc.UnaryInterceptor(SecurityInterceptorFunc(logger, config)), Loading @@ -70,6 +72,7 @@ func StartApiServer(logger *zap.Logger, db *sql.DB, jsonpbMarshaler *jsonpb.Mars runtimePool: runtimePool, tracker: tracker, router: router, socialClient: socialClient, grpcServer: grpcServer, } Loading
server/api_account.go +1 −1 Original line number Diff line number Diff line Loading @@ -27,7 +27,7 @@ import ( func (s *ApiServer) GetAccount(ctx context.Context, in *empty.Empty) (*api.Account, error) { userID := ctx.Value(ctxUserIDKey{}).(uuid.UUID) user, err := GetAccount(s.db, s.logger, userID) user, err := GetAccount(s.db, s.logger, s.tracker, userID) if err != nil { return nil, status.Error(codes.Internal, "Error retrieving user account.") } Loading
server/api_authenticate.go +115 −5 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import ( "github.com/dgrijalva/jwt-go" "github.com/heroiclabs/nakama/api" "github.com/satori/go.uuid" "golang.org/x/net/context" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" Loading Loading @@ -130,19 +131,128 @@ func (s *ApiServer) AuthenticateEmail(ctx context.Context, in *api.AuthenticateE } func (s *ApiServer) AuthenticateFacebook(ctx context.Context, in *api.AuthenticateFacebookRequest) (*api.Session, error) { return nil, nil if in.Account == nil || in.Account.Token == "" { return nil, status.Error(codes.InvalidArgument, "Facebook access token is required.") } username := in.Username username = strings.ToLower(username) if username == "" { 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 { return nil, status.Error(codes.InvalidArgument, "Username invalid, must be 1-128 bytes.") } create := in.Create == nil || in.Create.Value dbUserID, dbUsername, err := AuthenticateFacebook(s.logger, s.db, s.socialClient, in.Account.Token, username, create) if err != nil { return nil, err } // Import friends if requested. if in.Import == nil || in.Import.Value { importFacebookFriends(s.logger, s.db, s.socialClient, uuid.FromStringOrNil(dbUserID), dbUsername, in.Account.Token) } token := generateToken(s.config, dbUserID, dbUsername) return &api.Session{Token: token}, nil } func (s *ApiServer) AuthenticateGameCenter(ctx context.Context, in *api.AuthenticateGameCenterRequest) (*api.Session, error) { return nil, nil if in.Account == nil { return nil, status.Error(codes.InvalidArgument, "GameCenter access credentials are required.") } else if in.Account.BundleId == "" { return nil, status.Error(codes.InvalidArgument, "GameCenter bundle ID is required.") } else if in.Account.PlayerId == "" { return nil, status.Error(codes.InvalidArgument, "GameCenter player ID is required.") } else if in.Account.PublicKeyUrl == "" { return nil, status.Error(codes.InvalidArgument, "GameCenter public key URL is required.") } else if in.Account.Salt == "" { return nil, status.Error(codes.InvalidArgument, "GameCenter salt is required.") } else if in.Account.Signature == "" { return nil, status.Error(codes.InvalidArgument, "GameCenter signature is required.") } else if in.Account.TimestampSeconds == 0 { return nil, status.Error(codes.InvalidArgument, "GameCenter timestamp is required.") } username := in.Username username = strings.ToLower(username) if username == "" { 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 { return nil, status.Error(codes.InvalidArgument, "Username invalid, must be 1-128 bytes.") } create := in.Create == nil || in.Create.Value dbUserID, dbUsername, err := AuthenticateGameCenter(s.logger, s.db, s.socialClient, in.Account.PlayerId, in.Account.BundleId, in.Account.TimestampSeconds, in.Account.Salt, in.Account.Signature, in.Account.PublicKeyUrl, username, create) if err != nil { return nil, err } token := generateToken(s.config, dbUserID, dbUsername) return &api.Session{Token: token}, nil } func (s *ApiServer) AuthenticateGoogle(ctx context.Context, in *api.AuthenticateGoogleRequest) (*api.Session, error) { return nil, nil if in.Account == nil || in.Account.Token == "" { return nil, status.Error(codes.InvalidArgument, "Google access token is required.") } username := in.Username username = strings.ToLower(username) if username == "" { 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 { return nil, status.Error(codes.InvalidArgument, "Username invalid, must be 1-128 bytes.") } create := in.Create == nil || in.Create.Value dbUserID, dbUsername, err := AuthenticateGoogle(s.logger, s.db, s.socialClient, in.Account.Token, username, create) if err != nil { return nil, err } token := generateToken(s.config, dbUserID, dbUsername) return &api.Session{Token: token}, nil } func (s *ApiServer) AuthenticateSteam(ctx context.Context, in *api.AuthenticateSteamRequest) (*api.Session, error) { return nil, nil if s.config.GetSocial().Steam.PublisherKey == "" || s.config.GetSocial().Steam.AppID == 0 { return nil, status.Error(codes.FailedPrecondition, "Steam authentication is not configured.") } if in.Account == nil || in.Account.Token == "" { return nil, status.Error(codes.InvalidArgument, "Steam access token is required.") } username := in.Username username = strings.ToLower(username) if username == "" { 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 { return nil, status.Error(codes.InvalidArgument, "Username invalid, must be 1-128 bytes.") } create := in.Create == nil || in.Create.Value dbUserID, dbUsername, err := AuthenticateSteam(s.logger, s.db, s.socialClient, s.config.GetSocial().Steam.AppID, s.config.GetSocial().Steam.PublisherKey, in.Account.Token, username, create) if err != nil { return nil, err } token := generateToken(s.config, dbUserID, dbUsername) return &api.Session{Token: token}, nil } func generateToken(config Config, userID, username string) string { Loading
server/api_friend.go +1 −1 Original line number Diff line number Diff line Loading @@ -27,7 +27,7 @@ import ( func (s *ApiServer) ListFriends(ctx context.Context, in *empty.Empty) (*api.Friends, error) { userID := ctx.Value(ctxUserIDKey{}).(uuid.UUID) friends, err := GetFriends(s.logger, s.db, userID) friends, err := GetFriends(s.logger, s.db, s.tracker, userID) if err != nil { return nil, status.Error(codes.Internal, "Error while trying to list friends.") } Loading