Appstore服务器通知设置[接收App Store服务器通知版本2]

Lim*_*Jee 4 in-app-purchase ios in-app-purchase-receipt

我正在尝试使用应用商店通知设置我的服务器。\n以便当用户退款应用内购买时我可以收到通知。\n https://developer.apple.com/documentation/appstoreservernotifications/receiving_app_store_server_notifications <- 指南我现在正在寻找。

\n
The version 2 response body, responseBodyV2, contains a signedPayload that\xe2\x80\x99s cryptographically signed by the App Store in JSON Web Signature (JWS) format. The JWS format increases security and enables you to decode and validate the signature on your server. The notification data contains transaction and subscription renewal information that the App Store signs in JWS. The App Store Server API and the StoreKit In-App Purchase API use the same JWS-signed format for transaction and subscription status information. For more information about JWS, see the IETF RFC 7515 specification.\n
Run Code Online (Sandbox Code Playgroud)\n

根据文章,似乎我必须在与 App Store Connect 共享的 url 中保存签名的有效负载代码。\n https://gist.github.com/atpons/5279af568cb7d1b101247c02f0a022af \n<- 思考代码会看起来像这样
\n所以我的问题是,

\n

我是否需要制作一些新的私钥并与服务器开发人员共享?\n看起来我们从此处存储密钥https://www.apple.com/certificateauthority/\n并在我们请求时使用它?\n我如何收到通知?\n我是否应该期望\n预期的响应json结构\n这种通知将到达我与我的App Store Connect共享的url。\n感谢您阅读我的问题!

\n

小智 5

我按照以下步骤操作:

  1. 获取Apple根证书:wget https://www.apple.com/certificateauthority/AppleRootCA-G3.cer
  2. 创建pem文件:openssl x509 -inform der -in ./AppleRootCA-G3.cer -out ./apple_root.pem
  3. 运行代码:

import { X509Certificate } from 'crypto'
import fs from 'fs'
import jwt from 'jsonwebtoken'

// parameter
const signedPayloadFile = 'path to signedPayload file, ex: /home/vannguyen/signedPayload.txt'
const appleRootPemFile = 'path to pem file in step 2, ex: /home/vannguyen/apple_root.pem'
// end

const signedPayload = fs.readFileSync(signedPayloadFile).toString()

const decodeToken = (token, segment) => {
  const tokenDecodablePart = token.split('.')[segment]
  const decoded = Buffer.from(tokenDecodablePart, 'base64').toString()
  return decoded
}

const { alg, x5c } = JSON.parse(decodeToken(signedPayload, 0))

const x5cCertificates = x5c.map(
  (header) => new X509Certificate(Buffer.from(header, 'base64'))
)
const appleRootCertificate = new X509Certificate(
  fs.readFileSync(appleRootPemFile)
)

const checkIssued = appleRootCertificate.checkIssued(
  x5cCertificates[x5cCertificates.length - 1]
)
if (!checkIssued) {
  throw new Error('Invalid token')
}

x5cCertificates.push(appleRootCertificate)

const verifierStatuses = x5cCertificates.map((x590, index) => {
  if (index >= x5cCertificates.length - 1) return true
  return x590.verify(x5cCertificates[index + 1].publicKey)
})
if (verifierStatuses.includes(false)) {
  throw new Error('Invalid token')
}
const { publicKey } = x5cCertificates[0]
const payload = JSON.parse(decodeToken(signedPayload, 1))

const transactionInfo = jwt.verify(
  payload.data.signedTransactionInfo,
  publicKey,
  {
    algorithms: alg
  }
)

console.log('transactionInfo: ', transactionInfo)

const transactionRenewalInfo = jwt.verify(
  payload.data.signedRenewalInfo,
  publicKey,
  {
    algorithms: alg
  }
)

console.log('transactionRenewalInfo: ', transactionRenewalInfo)
Run Code Online (Sandbox Code Playgroud)