Unverified Commit 64d36359 authored by Simon Esposito's avatar Simon Esposito Committed by GitHub
Browse files

Add Apple IAP validation secret override. (#640)

Allow PurchaseValidateApple to be called with an optional parameter to override the configured Apple shared password.
Fix JS runtime storageList bug
parent f967c718
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -13,7 +13,7 @@ require (
	github.com/gorilla/mux v1.8.0
	github.com/gorilla/websocket v1.4.2
	github.com/grpc-ecosystem/grpc-gateway/v2 v2.3.0
	github.com/heroiclabs/nakama-common v1.14.1-0.20210628193431-8ff23c118581
	github.com/heroiclabs/nakama-common v1.14.1-0.20210707135714-ed381a338271
	github.com/jackc/pgconn v1.8.1
	github.com/jackc/pgerrcode v0.0.0-20201024163028-a0d42d470451
	github.com/jackc/pgtype v1.7.0
+2 −4
+9 −3
Original line number Diff line number Diff line
@@ -1947,10 +1947,16 @@ func (n *RuntimeGoNakamaModule) TournamentRecordsHaystack(ctx context.Context, i
	return TournamentRecordsHaystack(ctx, n.logger, n.db, n.leaderboardCache, n.leaderboardRankCache, id, owner, limit, expiry)
}

func (n *RuntimeGoNakamaModule) PurchaseValidateApple(ctx context.Context, userID, receipt string) (*api.ValidatePurchaseResponse, error) {
	if n.config.GetIAP().Apple.SharedPassword == "" {
func (n *RuntimeGoNakamaModule) PurchaseValidateApple(ctx context.Context, userID, receipt string, passwordOverride ...string) (*api.ValidatePurchaseResponse, error) {
	if n.config.GetIAP().Apple.SharedPassword == "" && len(passwordOverride) == 0 {
		return nil, errors.New("Apple IAP is not configured.")
	}
	password := n.config.GetIAP().Apple.SharedPassword
	if len(passwordOverride) > 1 {
		return nil, errors.New("Expects a single password override parameter")
	} else if len(passwordOverride) == 1 {
		password = passwordOverride[0]
	}

	uid, err := uuid.FromString(userID)
	if err != nil {
@@ -1961,7 +1967,7 @@ func (n *RuntimeGoNakamaModule) PurchaseValidateApple(ctx context.Context, userI
		return nil, errors.New("receipt cannot be empty string")
	}

	validation, err := ValidatePurchasesApple(ctx, n.logger, n.db, uid, n.config.GetIAP().Apple.SharedPassword, receipt)
	validation, err := ValidatePurchasesApple(ctx, n.logger, n.db, uid, password, receipt)
	if err != nil {
		return nil, err
	}
+30 −21
Original line number Diff line number Diff line
@@ -3231,31 +3231,32 @@ func (n *runtimeJavascriptNakamaModule) walletLedgerList(r *goja.Runtime) func(g

func (n *runtimeJavascriptNakamaModule) storageList(r *goja.Runtime) func(goja.FunctionCall) goja.Value {
	return func(f goja.FunctionCall) goja.Value {
		userIDString := ""
		if f.Argument(0) != goja.Undefined() {
			userIDString = getJsString(r, f.Argument(0))
		}
		uid, err := uuid.FromString(userIDString)
		var uid *uuid.UUID
		if f.Argument(0) != goja.Undefined() && f.Argument(0) != goja.Null() {
			userIDString := getJsString(r, f.Argument(0))
			u, err := uuid.FromString(userIDString)
			if err != nil {
				panic(r.NewTypeError("expects empty or valid user id"))
			}
			uid = &u
		}

		collection := ""
		if f.Argument(1) != goja.Undefined() {
		if f.Argument(1) != goja.Undefined() && f.Argument(1) != goja.Null() {
			collection = getJsString(r, f.Argument(1))
		}

		limit := 100
		if f.Argument(2) != goja.Undefined() {
		if f.Argument(2) != goja.Undefined() && f.Argument(2) != goja.Null() {
			limit = int(getJsInt(r, f.Argument(2)))
		}

		cursor := ""
		if f.Argument(3) != goja.Undefined() {
		if f.Argument(3) != goja.Undefined() && f.Argument(3) != goja.Null() {
			cursor = getJsString(r, f.Argument(3))
		}

		objectList, _, err := StorageListObjects(context.Background(), n.logger, n.db, uuid.Nil, &uid, collection, limit, cursor)
		objectList, _, err := StorageListObjects(context.Background(), n.logger, n.db, uuid.Nil, uid, collection, limit, cursor)

		objects := make([]interface{}, 0, len(objectList.Objects))
		for _, o := range objectList.Objects {
@@ -4115,7 +4116,7 @@ func (n *runtimeJavascriptNakamaModule) leaderboardRecordsList(r *goja.Runtime)
		var ownerIds []string
		owners := f.Argument(1)
		if owners != nil {
			if owners == goja.Undefined() {
			if owners == goja.Undefined() || owners == goja.Null() {
				panic(r.NewTypeError("expects an array of owner ids or null"))
			}
			ownersSlice, ok := owners.Export().([]interface{})
@@ -4128,26 +4129,29 @@ func (n *runtimeJavascriptNakamaModule) leaderboardRecordsList(r *goja.Runtime)
				if !ok {
					panic(r.NewTypeError("expects a valid owner string"))
				}
				if _, err := uuid.FromString(ownerStr); err != nil {
					panic(r.NewTypeError("expects a valid owner id"))
				}
				ownerIds = append(ownerIds, ownerStr)
			}
		}

		limitNumber := 0
		if f.Argument(2) != goja.Undefined() {
			limitNumber = int(getJsInt(r, f.Argument(2)))
		var limitNumber int32
		if f.Argument(2) != goja.Undefined() && f.Argument(2) != goja.Null() {
			limitNumber = int32(getJsInt(r, f.Argument(2)))
		}
		var limit *wrapperspb.Int32Value
		if limitNumber != 0 {
			limit = &wrapperspb.Int32Value{Value: int32(limitNumber)}
			limit = &wrapperspb.Int32Value{Value: limitNumber}
		}

		cursor := ""
		if f.Argument(3) != goja.Undefined() {
		if f.Argument(3) != goja.Undefined() && f.Argument(3) != goja.Null() {
			cursor = getJsString(r, f.Argument(3))
		}

		overrideExpiry := int64(0)
		if f.Argument(4) != goja.Undefined() {
		if f.Argument(4) != goja.Undefined() && f.Argument(4) != goja.Null() {
			overrideExpiry = getJsInt(r, f.Argument(4))
		}

@@ -4307,7 +4311,12 @@ func (n *runtimeJavascriptNakamaModule) leaderboardsGetId(r *goja.Runtime) func(

func (n *runtimeJavascriptNakamaModule) purchaseValidateApple(r *goja.Runtime) func(goja.FunctionCall) goja.Value {
	return func(f goja.FunctionCall) goja.Value {
		if n.config.GetIAP().Apple.SharedPassword == "" {
		password := n.config.GetIAP().Apple.SharedPassword
		if f.Argument(2) != goja.Undefined() {
			password = getJsString(r, f.Argument(2))
		}

		if password == "" {
			panic(r.NewGoError(errors.New("Apple IAP is not configured.")))
		}

@@ -4325,7 +4334,7 @@ func (n *runtimeJavascriptNakamaModule) purchaseValidateApple(r *goja.Runtime) f
			panic(r.NewTypeError("expects receipt"))
		}

		validation, err := ValidatePurchasesApple(context.Background(), n.logger, n.db, uid, n.config.GetIAP().Apple.SharedPassword, receipt)
		validation, err := ValidatePurchasesApple(context.Background(), n.logger, n.db, uid, password, receipt)
		if err != nil {
			panic(r.NewGoError(fmt.Errorf("error validating Apple receipt: %s", err.Error())))
		}
@@ -4775,7 +4784,7 @@ func leaderboardRecordsToJs(r *goja.Runtime, records []*api.LeaderboardRecord, o
		}
		recordMap["score"] = record.Score
		recordMap["subscore"] = record.Subscore
		recordMap["numScoore"] = record.NumScore
		recordMap["numScore"] = record.NumScore
		metadataMap := make(map[string]interface{})
		err := json.Unmarshal([]byte(record.Metadata), &metadataMap)
		if err != nil {
+3 −2
Original line number Diff line number Diff line
@@ -5802,7 +5802,8 @@ func leaderboardToLuaTable(l *lua.LState, leaderboard *api.Leaderboard) (*lua.LT
}

func (n *RuntimeLuaNakamaModule) purchaseValidateApple(l *lua.LState) int {
	if n.config.GetIAP().Apple.SharedPassword == "" {
	password := l.OptString(3, n.config.GetIAP().Apple.SharedPassword)
	if password == "" {
		l.RaiseError("Apple IAP is not configured.")
		return 0
	}
@@ -5824,7 +5825,7 @@ func (n *RuntimeLuaNakamaModule) purchaseValidateApple(l *lua.LState) int {
		return 0
	}

	validation, err := ValidatePurchasesApple(l.Context(), n.logger, n.db, userID, n.config.GetIAP().Apple.SharedPassword, receipt)
	validation, err := ValidatePurchasesApple(l.Context(), n.logger, n.db, userID, password, receipt)
	if err != nil {
		l.RaiseError("error validating Apple receipt: %v", err.Error())
		return 0
Loading