Skip to content
Snippets Groups Projects
Select Git revision
  • fa2b7259984b9e14259928e0f42cc52a82e63b69
  • gos-master default protected
  • gos-username
  • combinations
  • master
  • gos-build
  • gos-combinations
  • ff-spe-upgrade-pgx-v5-migrate
  • ft-optimized-storage-read
  • luke/better-steam-logs
  • ft-adjust-storage-star-write
  • binary-uuid
  • spe-upgrade-pgx-v5-migrate
  • aim-matchmaker-hook
  • ft-multiplatform-dockerimg
  • spe-correct-proto-bearer-sec-header
  • storage-no-read
  • onconflict-fix
  • spe-add-subscription-raw-response
  • ft-messages-haystack
  • mm-countmultiple-fix
  • v3.20.0-gos-2
  • v3.20.0-gos-1
  • v3.20.0
  • v3.19.0-gos-1
  • v3.19.0
  • v3.18.0
  • v3.17.1
  • v3.17.0
  • v3.16.0
  • v3.15.0
  • v3.14.0
  • v3.13.1
  • v3.13.0
  • v3.12.0
  • v3.11.0
  • v3.10.0
  • v3.9.0
  • v3.8.0
  • v3.7.0
  • v3.6.0
41 results

core_purchase.go

Blame
    • Simon Esposito's avatar
      fa2b7259
      Add iap refund support (#959) · fa2b7259
      Simon Esposito authored
      Add subscription raw response/notification.
      Add userID to validated purchases/subscriptions.
      Add Google refund scheduler.
      Handle Google IAP refunds by polling their voided purchases API.
      Invoke custom hooks on refund/subscription notification handling.
      Add iap refund support (#959)
      Simon Esposito authored
      Add subscription raw response/notification.
      Add userID to validated purchases/subscriptions.
      Add Google refund scheduler.
      Handle Google IAP refunds by polling their voided purchases API.
      Invoke custom hooks on refund/subscription notification handling.
    core_purchase.go 21.47 KiB
    // Copyright 2018 The Nakama Authors
    //
    // Licensed under the Apache License, Version 2.0 (the "License");
    // you may not use this file except in compliance with the License.
    // You may obtain a copy of the License at
    //
    // http://www.apache.org/licenses/LICENSE-2.0
    //
    // Unless required by applicable law or agreed to in writing, software
    // distributed under the License is distributed on an "AS IS" BASIS,
    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    // See the License for the specific language governing permissions and
    // limitations under the License.
    
    package server
    
    import (
    	"bytes"
    	"context"
    	"database/sql"
    	"encoding/base64"
    	"encoding/gob"
    	"errors"
    	"fmt"
    	"net/http"
    	"strconv"
    	"strings"
    	"time"
    
    	"github.com/gofrs/uuid"
    	"github.com/heroiclabs/nakama-common/api"
    	"github.com/heroiclabs/nakama/v3/iap"
    	"github.com/jackc/pgtype"
    	"go.uber.org/zap"
    	"google.golang.org/grpc/codes"
    	"google.golang.org/grpc/status"
    	"google.golang.org/protobuf/types/known/timestamppb"
    )
    
    var ErrPurchasesListInvalidCursor = errors.New("purchases list cursor invalid")
    
    var httpc = &http.Client{Timeout: 5 * time.Second}
    
    func ValidatePurchasesApple(ctx context.Context, logger *zap.Logger, db *sql.DB, userID uuid.UUID, password, receipt string, persist bool) (*api.ValidatePurchaseResponse, error) {
    	validation, raw, err := iap.ValidateReceiptApple(ctx, httpc, receipt, password)
    	if err != nil {
    		if err != context.Canceled {
    			var vErr *iap.ValidationError
    			if errors.As(err, &vErr) {
    				logger.Error("Error validating Apple receipt", zap.Error(vErr.Err), zap.Int("status_code", vErr.StatusCode), zap.String("payload", vErr.Payload))
    				return nil, vErr
    			} else {
    				logger.Error("Error validating Apple receipt", zap.Error(err))
    			}
    		}
    		return nil, err
    	}
    
    	if validation.Status != iap.AppleReceiptIsValid {
    		if validation.IsRetryable == true {
    			return nil, status.Error(codes.Unavailable, "Apple IAP verification is currently unavailable. Try again later.")
    		}
    		return nil, status.Error(codes.FailedPrecondition, fmt.Sprintf("Invalid Receipt. Status: %d", validation.Status))
    	}
    
    	env := api.StoreEnvironment_PRODUCTION
    	if validation.Environment == iap.AppleSandboxEnvironment {
    		env = api.StoreEnvironment_SANDBOX
    	}