feat(avatar): add signed Huihui virtual payment callback
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import hashlib
|
||||
import hmac
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
from unittest.mock import patch
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
@@ -14,6 +16,69 @@ from services.token_billing import DEFAULT_TOKEN_GRANT
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
def _huihui_virtual_headers(secret, body, timestamp=None):
|
||||
timestamp = str(timestamp if timestamp is not None else int(time.time()))
|
||||
signature = hmac.new(secret.encode(), timestamp.encode() + b"\n" + body, hashlib.sha256).hexdigest()
|
||||
return {"X-Huihui-Timestamp": timestamp, "X-Huihui-Signature": signature}
|
||||
|
||||
|
||||
def test_huihui_virtual_callback_requires_signature_and_exact_order_details(authorization_context):
|
||||
seed()
|
||||
context = authorization_context
|
||||
db = SessionLocal()
|
||||
try:
|
||||
user = db.query(User).filter(User.id == context["owner"].id).one()
|
||||
user.wechat_mp_openid = "openid-huihui-callback"
|
||||
user.wechat_mp_session_key = "session-huihui-callback"
|
||||
plan = db.query(TokenPlan).filter(TokenPlan.id == "1").one()
|
||||
plan.virtual_product_id = "points_plan_1"
|
||||
db.commit()
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
secret = "huihui-virtual-callback-test-secret-123456"
|
||||
env = {
|
||||
"WECHAT_VIRTUAL_ENV": "sandbox",
|
||||
"WECHAT_VIRTUAL_SANDBOX_APP_KEY": "sandbox-key",
|
||||
"WECHAT_VIRTUAL_OFFER_ID": "offer-1",
|
||||
"HUIHUI_VIRTUAL_CALLBACK_SECRET": secret,
|
||||
}
|
||||
with patch.dict(os.environ, env):
|
||||
created = client.post(
|
||||
"/api/token/charge",
|
||||
headers=context["owner_headers"],
|
||||
json={"planId": "1", "paymentMethod": "wechat", "payScene": "LITE"},
|
||||
).json()["data"]
|
||||
payload = {
|
||||
"orderNo": created["orderNo"],
|
||||
"paymentNo": f"huihui-virtual-payment-{context['suffix']}",
|
||||
"status": "SUCCESS",
|
||||
"amountCents": 1000,
|
||||
"productId": "points_plan_1",
|
||||
"openId": "openid-huihui-callback",
|
||||
"env": 1,
|
||||
}
|
||||
path = "/api/token/payment/huihui/virtual/notify"
|
||||
body = json.dumps(payload, separators=(",", ":")).encode()
|
||||
assert client.post(path, content=body, headers=_huihui_virtual_headers(secret, body, 1)).status_code == 401
|
||||
assert client.post(path, content=body, headers={"X-Huihui-Timestamp": str(int(time.time())), "X-Huihui-Signature": "bad"}).status_code == 401
|
||||
wrong = json.dumps({**payload, "amountCents": 999}, separators=(",", ":")).encode()
|
||||
assert client.post(path, content=wrong, headers=_huihui_virtual_headers(secret, wrong)).status_code == 422
|
||||
first = client.post(path, content=body, headers=_huihui_virtual_headers(secret, body))
|
||||
second = client.post(path, content=body, headers=_huihui_virtual_headers(secret, body))
|
||||
|
||||
assert first.json()["data"] == {"received": True, "paid": True}
|
||||
assert second.json()["data"] == {"received": True, "duplicate": True}
|
||||
db = SessionLocal()
|
||||
try:
|
||||
order = db.query(TokenPaymentOrder).filter(TokenPaymentOrder.order_no == created["orderNo"]).one()
|
||||
account = db.query(TokenAccount).filter(TokenAccount.user_id == context["owner"].id).one()
|
||||
assert order.status == "paid"
|
||||
assert account.balance == DEFAULT_TOKEN_GRANT + 2_000_000
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
def _signature(token, timestamp, nonce):
|
||||
return hashlib.sha1("".join(sorted([token, timestamp, nonce])).encode()).hexdigest()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user