Files
aigrammar/iap.go
2024-08-17 04:29:48 +00:00

179 lines
6.8 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"context"
"encoding/json"
"io"
"net/http"
"net/url"
"strings"
"github.com/awa/go-iap/appstore/api"
"github.com/labstack/echo/v4"
"go.uber.org/zap"
)
// 处理appstore的回调
func IapCallbackHandler(c echo.Context) error {
// 获取请求体
body, err := io.ReadAll(c.Request().Body) // {"signedPayload":"..."}
if err != nil {
logger.Error("Failed to read request body", zap.Error(err))
return echo.NewHTTPError(http.StatusBadRequest, "read body error.")
//return c.JSON(http.StatusInternalServerError, "Failed to read request body")
}
// App Store Server Notification Request JSON String
var request AppStoreServerRequest
err2 := json.Unmarshal([]byte(body), &request) // bind byte to header structure
if err2 != nil {
logger.Error("AppStoreServerRequest Unmarshal error.", zap.Error(err))
return echo.NewHTTPError(http.StatusBadRequest, "Failed to read request body")
}
// Apple Root CA - G3 Root certificate
// for details: https://www.apple.com/certificateauthority/
// you need download it and covert it to a valid pem file in order to verify X5c certificates
// `openssl x509 -in AppleRootCA-G3.cer -out cert.pem`
appStoreServerNotification, err := IAP_Notify_New(request.SignedPayload, IAP_ROOT_CERT)
if err != nil {
logger.Error("IAP_Notify_New error.", zap.Error(err))
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to decode body")
}
// 打印字段,为了显示方便,把加密串替换掉
appStoreServerNotification.Payload.Data.SignedRenewalInfo = "..."
appStoreServerNotification.Payload.Data.SignedTransactionInfo = "..."
logger.Debug("appStoreServerNotification", zap.Any("appStoreServerNotification", appStoreServerNotification))
// 打印日志
//buff, _ := json.Marshal(&appStoreServerNotification)
//fmt.Println(string(buff))
UpdateOrderByNotify(appStoreServerNotification)
setResponse(c, nil)
return nil
}
// 处理从客户端过来的订单验证请求
func IapVerify(c echo.Context) error {
var request struct {
TransID string `json:"transid" form:"transid"`
AppAccountToken string `json:"appaccounttoken" form:"appaccounttoken"`
Env string `json:"env" form:"env"`
ProductID string `json:"productid" form:"productid"`
ReceiptData string `json:"receiptdata" form:"receiptdata"`
}
if err := c.Bind(&request); err != nil {
logger.Error("read param error.", zap.Error(err))
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
// 验证 receiptdata 是否为有效的 JSON 字符串
var jsonObj interface{}
if err := json.Unmarshal([]byte(request.ReceiptData), &jsonObj); err != nil {
logger.Debug("receiptdata from request", zap.Any("receiptdata", request.ReceiptData)) // 打印日志
} else {
logger.Error("receiptdata from request", zap.Any("receiptdata", request.ReceiptData)) // 打印日志
}
var isSandBox = true
// 忽略大小写进行比较
if strings.EqualFold(request.Env, "Production") {
isSandBox = false
}
cfg := &api.StoreConfig{
KeyContent: []byte(IAP_ACCOUNT_KEY), // Loads a .p8 certificate
KeyID: IAP_KEY_ID, // Your private key ID from App Store Connect (Ex: 2X9R4HXF34)
BundleID: IAP_BUNDLEID, // Your apps bundle ID
Issuer: IAP_ISSUER, // Your issuer ID from the Keys page in App Store Connect (Ex: "57246542-96fe-1a63-e053-0824d011072a")
Sandbox: isSandBox, // default is Production
}
client := api.NewStoreClient(cfg)
ctx := context.Background()
response, err := client.GetTransactionInfo(ctx, request.TransID)
if err != nil {
logger.Error("GetTransactionInfo error.", zap.Error(err))
return echo.NewHTTPError(http.StatusInternalServerError, "GetTransactionInfo error")
}
transantion, err := client.ParseSignedTransaction(response.SignedTransactionInfo)
if err != nil {
logger.Error("ParseSignedTransaction error.", zap.Error(err))
return echo.NewHTTPError(http.StatusInternalServerError, "ParseSignedTransaction error")
}
logger.Debug("transantion", zap.Any("transantion", transantion), zap.Any("request", request)) // 打印日志
//buff, _ := json.Marshal(&transantion)
//fmt.Println(string(buff))
if transantion.TransactionID != request.TransID {
logger.Error("transactionId not match.", zap.Any("transantion.TransactionID", transantion.TransactionID), zap.Any("request.TransID", request.TransID))
return echo.NewHTTPError(http.StatusInternalServerError, "transactionId not match")
}
// 写入DB
GID, _ := c.Get(KEY_GID).(int)
errDB := UpdateOrderByVerify(GID, request.AppAccountToken, transantion.OriginalTransactionId, transantion)
if errDB != nil {
logger.Error("UpdateOrderByVerify error.", zap.Error(errDB))
return echo.NewHTTPError(http.StatusInternalServerError, "UpdateOrderByVerify error")
}
setResponse(c, map[string]string{"ret": "ok"})
return nil
}
// 查询订单历史信息,通常是内部服务发起
func IapHistory(c echo.Context) error {
var request struct {
OriginTransID string `json:"origintransid" form:"origintransid"`
Lang string `json:"lang" form:"lang"`
}
if err := c.Bind(&request); err != nil {
logger.Error("read param error.", zap.Error(err))
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
cfg := &api.StoreConfig{
KeyContent: []byte(IAP_ACCOUNT_KEY), // Loads a .p8 certificate
KeyID: IAP_KEY_ID, // Your private key ID from App Store Connect (Ex: 2X9R4HXF34)
BundleID: IAP_BUNDLEID, // Your apps bundle ID
Issuer: IAP_ISSUER, // Your issuer ID from the Keys page in App Store Connect (Ex: "57246542-96fe-1a63-e053-0824d011072a")
Sandbox: true, // default is Production
}
client := api.NewStoreClient(cfg)
query := &url.Values{}
query.Set("productType", "AUTO_RENEWABLE")
//query.Set("productType", "NON_CONSUMABLE")
ctx := context.Background()
responses, err := client.GetTransactionHistory(ctx, request.OriginTransID, query)
if err != nil {
logger.Error("GetTransactionHistory error.", zap.Error(err))
return echo.NewHTTPError(http.StatusInternalServerError, "GetTransactionHistory error")
}
// 由于接口字段中有HasMore所以 responses 是个数组,每个 responses 中的 transantions 也是数组
var allTransactions []*api.JWSTransaction
for _, response := range responses {
transantions, err := client.ParseSignedTransactions(response.SignedTransactions)
if err != nil {
logger.Error("ParseSignedTransactions error.", zap.Error(err))
return echo.NewHTTPError(http.StatusInternalServerError, "ParseSignedTransactions error")
}
allTransactions = append(allTransactions, transantions...)
logger.Debug("transantions", zap.Any("transantions", transantions)) // 打印
//buff, _ := json.Marshal(&transantions)
//fmt.Println(string(buff))
}
setResponse(c, allTransactions)
//setResponse(c, map[string]string{"ret": "ok"})
return nil
}