fix(iap): 修复JWS验证逻辑,支持原始R||S签名格式
Build docker and publish / build (20.15.1) (push) Successful in 6m38s

fix(middleware): 增加设备中间件的日志记录
fix(auth): 优化认证中间件的错误日志记录
feat(iap): 添加苹果交易附加逻辑的详细日志
This commit is contained in:
2025-12-15 23:44:55 -08:00
parent 3c6dd5058b
commit e11ed2338d
4 changed files with 75 additions and 31 deletions
+30 -22
View File
@@ -6,6 +6,7 @@ import (
"crypto/x509"
"encoding/base64"
"encoding/json"
"math/big"
"strings"
"time"
"unicode"
@@ -21,20 +22,26 @@ func cleanB64(s string) string {
}, trimmed)
}
func decodeB64URL(s string) ([]byte, error) {
s = cleanB64(s)
if b, err := base64.RawURLEncoding.DecodeString(s); err == nil {
return b, nil
}
switch len(s) % 4 {
case 2:
s += "=="
case 3:
s += "="
}
return base64.URLEncoding.DecodeString(s)
}
func ParseTransactionJWS(jws string) (*TransactionPayload, error) {
parts := strings.Split(strings.TrimSpace(jws), ".")
if len(parts) != 3 {
return nil, ErrInvalidJWS
}
payloadB64 := cleanB64(parts[1])
// add padding if required
switch len(payloadB64) % 4 {
case 2:
payloadB64 += "=="
case 3:
payloadB64 += "="
}
data, err := base64.RawURLEncoding.DecodeString(payloadB64)
data, err := decodeB64URL(parts[1])
if err != nil {
return nil, err
}
@@ -78,15 +85,8 @@ func VerifyTransactionJWS(jws string) (*TransactionPayload, error) {
if len(parts) != 3 {
return nil, ErrInvalidJWS
}
hdrB64 := cleanB64(parts[0])
switch len(hdrB64) % 4 {
case 2:
hdrB64 += "=="
case 3:
hdrB64 += "="
}
var hdr jwsHeader
hdrBytes, err := base64.RawURLEncoding.DecodeString(hdrB64)
hdrBytes, err := decodeB64URL(parts[0])
if err != nil {
return nil, err
}
@@ -109,14 +109,22 @@ func VerifyTransactionJWS(jws string) (*TransactionPayload, error) {
return nil, ErrInvalidJWS
}
signingInput := cleanB64(parts[0]) + "." + cleanB64(parts[1])
sig := cleanB64(parts[2])
sigBytes, err := base64.RawURLEncoding.DecodeString(sig)
sigBytes, err := decodeB64URL(parts[2])
if err != nil {
return nil, err
}
d := sha256.Sum256([]byte(signingInput))
if !ecdsa.VerifyASN1(pub, d[:], sigBytes) {
return nil, ErrInvalidJWS
// Try ASN.1 signature first
if ecdsa.VerifyASN1(pub, d[:], sigBytes) {
return ParseTransactionJWS(jws)
}
return ParseTransactionJWS(jws)
// Fallback: raw R||S (JWS ES256 uses raw signature)
if len(sigBytes) == 64 {
r := new(big.Int).SetBytes(sigBytes[:32])
s := new(big.Int).SetBytes(sigBytes[32:])
if ecdsa.Verify(pub, d[:], r, s) {
return ParseTransactionJWS(jws)
}
}
return nil, ErrInvalidJWS
}