d7c29c0883
- rewards: 激励视频实发改按 calculate_ad_reward_coin(eCPM, 当日第N次) 公式;AD_REWARD_COIN/MAX_AD_REWARD_COIN 降为历史兼容口径;新增 SIGNIN_BOOST_COIN=2000 - 签到膨胀: Day1-13 看完激励视频额外发固定金币、Day14 不允许 (signin.py / signin-boost) - ad_session_id 幂等: ad_ecpm/ad_reward/ad_feed_reward 记录加 ad_session_id 列 + 唯一索引(新迁移 coin_reward_phase2 / ad_feed_reward_session) - ad.py + schemas + repositories: ecpm-report / feed-reward / reward-status / test-grant 改造;config_schema 增 signin_boost_coin;admin stats overview 补充 - 同步 docs/api + docs/database + docs/integrations/pangle 及 tests(test_ad_reward / test_welfare) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: OuYingJun1024 <1034284404@qq.com> Reviewed-on: #28 Co-authored-by: ouzhou <ouzhou@wonderable.ai> Co-committed-by: ouzhou <ouzhou@wonderable.ai>
45 lines
2.1 KiB
Python
45 lines
2.1 KiB
Python
"""穿山甲激励视频"服务端发奖回调"的验签。
|
|
|
|
发奖闭环:激励视频播完 → 穿山甲服务器 GET 回调本服务(带 user_id / trans_id / sign 等)
|
|
→ 本服务**验签**确认回调确实来自穿山甲(而非伪造请求) → 幂等发金币。
|
|
客户端不参与发奖,被破解也刷不到钱。
|
|
|
|
验签方案(穿山甲 GroMore「广告位 → 服务端激励回调」官方规范,见 supportcenter/26240。
|
|
我们客户端是 useMediation(true) 融合,回调走 GroMore 广告位层级,**不是**联盟代码位层级):
|
|
**sign = SHA256("{m-key}:{trans_id}")** 的十六进制串。注意:
|
|
- 是**普通 SHA256**,不是 HMAC,也不是 RSA;
|
|
- **只对 `m-key:trans_id` 这一个字符串**签名,user_id / ecpm / extra 等其余参数**不参与**签名
|
|
(它们的可信度由"能算出正确 sign = 知道 m-key"间接保证——伪造者没有 m-key 就连合法 sign
|
|
都造不出,自然也无法注入假 user_id/ecpm/extra)。
|
|
m-key(安全密钥)在穿山甲后台「GroMore 聚合管理 → 搜广告位ID → 编辑」处获取,配到
|
|
`settings.PANGLE_REWARD_SECRET`。(联盟代码位层级用的是另一套 Security Key + isValid 响应,我们不走那条。)
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import hashlib
|
|
import hmac
|
|
|
|
|
|
def build_sign(trans_id: str, secret: str) -> str:
|
|
"""按穿山甲规范计算 sign = SHA256("{SecurityKey}:{trans_id}") 的十六进制串。
|
|
|
|
secret 即后台的 Security Key。自验签测试 / 模拟回调脚本也用这一个函数,保证两端一致。
|
|
"""
|
|
msg = f"{secret}:{trans_id}".encode("utf-8")
|
|
return hashlib.sha256(msg).hexdigest()
|
|
|
|
|
|
def verify_callback_sign(params: dict[str, str], secret: str) -> bool:
|
|
"""校验回调签名。`params` 是回调全部 query 参数(含 sign / trans_id)。
|
|
|
|
密钥为空或缺 trans_id 一律判失败。比较用定长比较防时序侧信道。
|
|
"""
|
|
if not secret:
|
|
return False
|
|
trans_id = params.get("trans_id") or ""
|
|
if not trans_id:
|
|
return False
|
|
got = params.get("sign") or ""
|
|
expect = build_sign(trans_id, secret)
|
|
return hmac.compare_digest(got, expect)
|