fix(ad): 激励视频发奖按环境隔离,堵测试包看广告给生产同 id 用户串号发币 (#77)
## 问题 激励视频发奖走穿山甲 S2S 回调 /api/v1/ad/pangle-callback,发币时只认回调里的裸数字 user_id(grant_ad_reward 仅校验「本库存在该 id」),无任何环境归属校验。 同一 user_id 在测试库(本地 localhost)与正式库(线上)是两个不同的人;穿山甲 S2S 回调 地址只配一个(指向生产),测试包(dev)看广告的回调也会打到生产 → 生产把奖发给「本库里 同 user_id 的另一个真人」,造成跨库串号:测试看一次广告,正式库同号用户也被发币(线上 广告收益页因此多出一条本不该有的发奖记录)。 ## 修复(服务端,按环境隔离) pangle_callback 解析激励视频 mediaExtra 透传的 srv_env(dev/prod),与本服 settings.APP_ENV 不符则受理但不发币、不写记录(is_verify=true 防穿山甲重试)。不带 srv_env 的旧客户端按本 环境放行(兼容,不误伤存量正式用户)。 - 新增回归测试 test_callback_foreign_env_skipped(srv_env=prod 打到 APP_ENV=dev 的服务 → 不发) - sim_pangle_callback 增加 --srv-env 便于本地手验 客户端配套(mediaExtra 写入 srv_env)见 app-android 对应 PR。 ## 生效前提(三者缺一仍漏) 1. 生产 app-server 部署本代码并重启 2. 生产 .env 为 APP_ENV=prod 3. app 重新构建(旧包不带 srv_env 仍走兼容放行) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: zzhyyyyy <2685922758@qq.com> Reviewed-on: #77 Co-authored-by: zhuzihao <zhuzihao@wonderable.ai> Co-committed-by: zhuzihao <zhuzihao@wonderable.ai>
This commit was merged in pull request #77.
This commit is contained in:
@@ -120,6 +120,21 @@ def pangle_callback(request: Request, db: DbSession) -> PangleCallbackOut:
|
||||
ad_session_id = extra.get("ad_session_id")
|
||||
ecpm = params.get("ecpm")
|
||||
|
||||
# 环境隔离:激励视频 mediaExtra 里带「这次观看属于哪个后端环境」(srv_env=dev/prod,客户端按
|
||||
# BuildConfig.DEBUG 决定),穿山甲 S2S 回调原样带回。回调 URL 在穿山甲后台只配一个(指向生产),
|
||||
# 所以测试包(dev)看广告的 S2S 也会打到生产——若不拦,生产会把奖发给「本库里同 user_id 的另一个
|
||||
# 真人」(user_id 是跨库不隔离的裸数字 → 跨库串号)。这里只处理「属于本服环境」的回调:环境不符
|
||||
# 直接受理但不发币、不写任何记录,保证各环境后台广告收益页只含本环境用户。is_verify=true 让穿山甲
|
||||
# 不再重试(测试用户的币由 localhost 的 test-grant 单独发,不依赖这条 S2S)。
|
||||
# 兼容:旧客户端不带 srv_env(取不到)→ 视为本环境,照常处理,不误伤存量正式用户。
|
||||
callback_env = extra.get("srv_env")
|
||||
if callback_env and callback_env != settings.APP_ENV:
|
||||
logger.info(
|
||||
"pangle callback foreign env skip: callback_env=%s self_env=%s user_id=%d trans_id=%s",
|
||||
callback_env, settings.APP_ENV, user_id, trans_id,
|
||||
)
|
||||
return PangleCallbackOut(is_verify=True, reason=REASON_OK)
|
||||
|
||||
existing = crud_ad.find_by_trans(db, trans_id)
|
||||
if existing is not None:
|
||||
logger.info(
|
||||
|
||||
Reference in New Issue
Block a user