Skip to content

安全修复:加固初始化、OAuth 绑定鉴权、自动更新语支付回调校验 - #4504

Closed
ll539 wants to merge 4 commits into
QuantumNous:mainfrom
ll539:main
Closed

安全修复:加固初始化、OAuth 绑定鉴权、自动更新语支付回调校验#4504
ll539 wants to merge 4 commits into
QuantumNous:mainfrom
ll539:main

Conversation

@ll539

@ll539 ll539 commented Apr 28, 2026

Copy link
Copy Markdown

📝 变更描述 / Description

本次改动聚焦补齐几条高风险链路上的服务端校验,范围控制在初始化、OAuth 绑定、自助资料更新和支付回调四个模块,没有改数据库结构,也没有调整前端或接口字段。

具体包括:

  • 收紧 /api/setup:当系统已初始化,或数据库中已存在 root 用户时,直接拒绝再次初始化,避免部署状态异常时被重复调用或抢占 root。
  • 补上 OAuth 绑定接口的后端登录鉴权:/api/oauth/email/bind/api/oauth/wechat/bind/api/oauth/telegram/bind 统一挂载 UserAuth(),把“只能登录用户绑定”的约束放回服务端。
  • 收紧 UpdateSelf:普通用户自助更新改为白名单处理,只保留现有允许的自助字段,并显式拒绝 quotarolegroupstatusused_quotarequest_countaccess_token 等敏感字段,避免通过 overposting 修改权限、额度或身份相关信息。
  • 修正微信自动注册路径:未绑定微信用户在自动创建账号前会检查 RegisterEnabled,已绑定用户的正常登录流程保持不变。
  • 加固支付回调:在 Epay、Stripe、Creem、Waffo 现有签名、provider、pending 状态和幂等控制基础上,补充订单金额、订单归属和关键字段一致性校验,减少伪造回调、跨渠道回调、金额错单和重复入账风险。
  • 在关键拒绝点补充最小安全日志,便于排查问题,同时避免记录密码、密钥或完整 token。

这些改动复用了现有 middleware、controller 和 model 的处理路径,属于有边界的安全修复,不引入新的权限体系,也不改变正常支付和已绑定账号的既有业务流程。

🚀 变更类型 / Type of change

  • 🐛 Bug 修复 (Bug fix) - 请关联对应 Issue,避免将设计取舍、理解偏差或预期不一致直接归类为 bug
  • ✨ 新功能 (New feature) - 重大特性建议先通过 Issue 沟通
  • ⚡ 性能优化 / 重构 (Refactor)
  • 📝 文档更新 (Documentation)

🔗 关联任务 / Related Issue

  • Closes #

✅ 提交前检查项 / Checklist

  • 人工确认: 我已亲自整理并撰写此描述,没有直接粘贴未经处理的 AI 输出。
  • 非重复提交: 我已搜索现有的 IssuesPRs,确认不是重复提交。
  • Bug fix 说明: 若此 PR 标记为 Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。
  • 变更理解: 我已理解这些更改的工作原理及可能影响。
  • 范围聚焦: 本 PR 未包含任何与当前任务无关的代码改动。
  • 本地验证: 已在本地运行并通过测试或手动验证,维护者可以据此复核结果。
  • 安全合规: 代码中无敏感凭据,且符合项目代码规范。

📸 运行证明 / Proof of Work

本地已执行:

gofmt -w controller/setup.go router/api-router.go controller/user.go controller/wechat.go controller/topup.go controller/topup_stripe.go controller/topup_creem.go controller/topup_waffo.go
git diff --check
go build ./controller/...
go build ./model/...
go test ./controller/...
go test ./model/...

关键人工验收点:

  • 已存在 root 用户时,POST /api/setup 会被拒绝。
  • 未登录访问 /api/oauth/email/bind、/api/oauth/wechat/bind、/api/oauth/telegram/bind 会被服务端拒绝。
  • 普通用户通过 PUT /api/user/self 提交 quota/role/group/status 等敏感字段时,不会写入数据库。
  • RegisterEnabled=false 时,未绑定微信用户不会被自动注册;已绑定微信用户仍可正常登录。
  • 支付回调在金额不匹配、provider 不匹配或重复成功回调场景下不会重复或错误入账。

Summary by CodeRabbit

  • Security

    • OAuth binding endpoints (email, WeChat, Telegram) now require user authentication.
    • Account self-updates protected—sensitive fields (quota, balance, role, tokens) cannot be modified.
  • Improvements

    • Payment webhook validation strengthened with amount verification across all providers.
    • Enhanced logging for setup rejections and failed authentication attempts.

@coderabbitai

coderabbitai Bot commented Apr 28, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

The PR adds stricter validation and logging across payment webhook handlers for multiple providers (Topup, Creem, Stripe, Waffo), the user account setup endpoint, and user profile update operations. It also requires authentication middleware on OAuth binding routes and logs warning messages for rejected auth attempts and setup requests.

Changes

Cohort / File(s) Summary
Payment Webhook Validation
controller/topup.go, controller/topup_creem.go, controller/topup_stripe.go, controller/topup_waffo.go
Added stricter request-to-order consistency checks across payment providers: normalized amount comparison (2-decimal precision), payment provider verification, status validation (pending/success), and idempotency handling. Provider-specific validations include Creem product matching, Stripe currency enforcement (USD), and Waffo amount normalization. Invalid callbacks are rejected early with rejection logging instead of proceeding to recharge.
Account & User Updates
controller/setup.go, controller/user.go
Added warning logs to setup endpoint when rejecting completed setups or root-user conflicts. Added field-level filtering to user self-updates: blocks sensitive fields (quota, balance, role, status, tokens) and enforces single-key payloads for setting-only modes; general updates now use strict allowlisting with explicit typed extraction.
Authentication & Logging
controller/wechat.go
Added warning log with contextual details (wechat\_id, client\_ip) when rejecting new WeChat user auto-registration due to disabled registration setting.
Router Middleware
router/api-router.go
Added middleware.UserAuth() authentication requirement to OAuth binding endpoints: POST /api/oauth/email/bind, POST /api/oauth/wechat/bind, GET /api/oauth/telegram/bind.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • 新增 creem 支付 #1823: Directly modifies Creem webhook/order handling in controller/topup\_creem.go for checkout.completed validation flow.
  • main -> alpha #1954: Modifies SetApiRouter in router/api-router.go for route middleware and authentication configuration.

Suggested reviewers

  • seefs001

Poem

🐰 A careful hop through payment flows,
With validations that we chose,
Each webhook checked, amounts aligned,
Security and logic intertwined,
No shortcuts now—just solid ground,
Where trusty validation can be found!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title comprehensively addresses all major security-focused changes across the PR: initialization hardening (setup.go), OAuth binding authentication (router/api-router.go), self-service payment callback validation (topup*.go), and user update restrictions (user.go).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
controller/user.go (1)

661-679: ⚠️ Potential issue | 🟡 Minor

Reject non-string sidebar_modules / language payloads instead of returning success.

Both special-case branches only update on string, but they currently fall through to MsgUpdateSuccess when the caller sends an object/array/number. That turns malformed input into a silent no-op and weakens the strict validation this PR adds elsewhere.

🛠️ Proposed fix
 	// 更新sidebar_modules字段
-	if sidebarModulesStr, ok := sidebarModules.(string); ok {
-		currentSetting.SidebarModules = sidebarModulesStr
-	}
+	sidebarModulesStr, ok := sidebarModules.(string)
+	if !ok {
+		common.ApiErrorI18n(c, i18n.MsgInvalidParams)
+		return
+	}
+	currentSetting.SidebarModules = sidebarModulesStr
@@
 	// 更新language字段
-	if langStr, ok := language.(string); ok {
-		currentSetting.Language = langStr
-	}
+	langStr, ok := language.(string)
+	if !ok {
+		common.ApiErrorI18n(c, i18n.MsgInvalidParams)
+		return
+	}
+	currentSetting.Language = langStr

Also applies to: 693-710

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@controller/user.go` around lines 661 - 679, The code currently ignores
non-string payloads for "sidebar_modules" (and similarly for "language") and
returns success; change the handlers so that when requestData["sidebar_modules"]
(and requestData["language"] in the other branch) exists but is not a string you
call common.ApiErrorI18n(c, i18n.MsgInvalidInput) and return instead of
proceeding to success; locate the logic around requestData, user.GetSetting(),
and currentSetting.SidebarModules in controller/user.go (and the parallel branch
at the other block) and add an explicit type-check rejection path so only string
values are accepted before assigning and saving and before emitting
MsgUpdateSuccess.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@controller/topup_stripe.go`:
- Around line 283-314: The webhook wrongly hardcodes "USD" when validating
currency; update the flow to store the expected currency on the order when
creating the Stripe checkout session (the code that uses setting.StripePriceId)
and then use that stored value in the callback instead of "USD". Specifically:
add/persist an expected currency field on the TopUp record when creating the
Stripe session (lookup the Price/currency or read it from the created session in
the checkout creation code), populate topUp.Currency (or similar) there, and
change the callback logic that currently calls event.GetObjectValue("currency")
and compares to "USD" to compare against topUp.Currency (case-normalized) and
log appropriately via logPaymentReject / logger.LogWarn when mismatched. Ensure
GetTopUpByTradeNo, topUp.PaymentProvider, topUp.Status, and the amount checks
remain unchanged.

In `@controller/topup.go`:
- Around line 373-403: The handler currently writes "success" before performing
the critical post-payment operations, so move the
c.Writer.Write([]byte("success")) call to after the locked update/quota-credit
block (i.e., only after topUp.Update() and IncreaseUserQuota() succeed); if
either topUp.Update() or IncreaseUserQuota() fails, log the error (use
logger.LogError or existing logPaymentReject), write "fail" and return so the
gateway can retry. Locate code paths using GetTopUpByTradeNo,
normalizeMoneyDecimalFromFloat/FromString, logPaymentReject, and the subsequent
topUp.Update()/IncreaseUserQuota() calls and ensure acknowledgement is
conditional on their success. Ensure all early reject paths still write "fail"
immediately.

In `@controller/wechat.go`:
- Line 108: The warning log currently prints the raw external account identifier
wechatId in the logger.LogWarn call; update the code that calls logger.LogWarn
(the site using wechatId and c.ClientIP()) to avoid logging raw PII by deriving
and logging a non-reversible fingerprint (e.g., hash like SHA256 and truncate to
a short fixed length) or a truncated masked form of wechatId instead, and keep
c.ClientIP() as-is; ensure the new value replaces wechatId in the fmt.Sprintf
invocation so only the hashed/truncated/masked identifier is written to logs.

In `@router/api-router.go`:
- Around line 39-44: The bind routes now allow Authorization header auth via
middleware.UserAuth(), but the handlers EmailBind, WeChatBind, and TelegramBind
still read sessions.Default(c).Get("id").(int) and will panic on
access-token-only requests; update those handlers to safely read the
authenticated user id from the request context (use c.GetInt("id") or equivalent
context value set by UserAuth()) instead of casting session values, or
alternatively remove middleware.UserAuth() from these routes and enforce a
session-only guard so sessions.Default(c).Get("id") is always present; modify
either the middleware usage in router/api-router.go or the handlers (EmailBind,
WeChatBind, TelegramBind) accordingly to ensure no nil session lookup occurs.

---

Outside diff comments:
In `@controller/user.go`:
- Around line 661-679: The code currently ignores non-string payloads for
"sidebar_modules" (and similarly for "language") and returns success; change the
handlers so that when requestData["sidebar_modules"] (and
requestData["language"] in the other branch) exists but is not a string you call
common.ApiErrorI18n(c, i18n.MsgInvalidInput) and return instead of proceeding to
success; locate the logic around requestData, user.GetSetting(), and
currentSetting.SidebarModules in controller/user.go (and the parallel branch at
the other block) and add an explicit type-check rejection path so only string
values are accepted before assigning and saving and before emitting
MsgUpdateSuccess.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 76846162-f566-4052-bb2c-a70cce55d0db

📥 Commits

Reviewing files that changed from the base of the PR and between 9f8a4ec and 049a3f7.

📒 Files selected for processing (8)
  • controller/setup.go
  • controller/topup.go
  • controller/topup_creem.go
  • controller/topup_stripe.go
  • controller/topup_waffo.go
  • controller/user.go
  • controller/wechat.go
  • router/api-router.go

Comment thread controller/topup_creem.go
Comment on lines +354 to +377
var products []CreemProduct
if err := common.UnmarshalJsonStr(setting.CreemProducts, &products); err == nil {
var matchedProducts []CreemProduct
for _, product := range products {
if product.Quota == topUp.Amount && decimal.NewFromFloat(product.Price).Round(2).Equal(expectedAmount) {
matchedProducts = append(matchedProducts, product)
}
}
if len(matchedProducts) == 1 {
expectedProduct := matchedProducts[0]
if expectedProduct.ProductId != "" && event.Object.Product.Id != expectedProduct.ProductId {
logger.LogWarn(c.Request.Context(), fmt.Sprintf("Creem callback rejected provider=%s trade_no=%s reason=product_mismatch expected_product=%s actual_product=%s client_ip=%s", model.PaymentProviderCreem, referenceId, expectedProduct.ProductId, event.Object.Product.Id, c.ClientIP()))
c.AbortWithStatus(http.StatusBadRequest)
return
}
expectedCurrency := strings.ToUpper(expectedProduct.Currency)
actualCurrency := strings.ToUpper(event.Object.Order.Currency)
if expectedCurrency != "" && actualCurrency != expectedCurrency {
logger.LogWarn(c.Request.Context(), fmt.Sprintf("Creem callback rejected provider=%s trade_no=%s reason=currency_mismatch expected_currency=%s actual_currency=%s client_ip=%s", model.PaymentProviderCreem, referenceId, expectedCurrency, actualCurrency, c.ClientIP()))
c.AbortWithStatus(http.StatusBadRequest)
return
}
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Do not silently skip product/currency validation when the config is ambiguous or unreadable.

If CreemProducts fails to parse, or multiple configured products share the same (quota, price) pair, this branch falls through and accepts the callback on amount alone. That makes the new product/currency check best-effort instead of authoritative. Persist the selected product_id/currency with the local order and compare against those exact values here, or reject when the config cannot identify a unique match.

Comment on lines +283 to +314
topUp := model.GetTopUpByTradeNo(referenceId)
if topUp == nil {
logger.LogWarn(ctx, fmt.Sprintf("Stripe callback rejected provider=%s trade_no=%s reason=order_not_found client_ip=%s", model.PaymentProviderStripe, referenceId, callerIp))
return
}
if topUp.PaymentProvider != model.PaymentProviderStripe {
logger.LogWarn(ctx, fmt.Sprintf("Stripe callback rejected provider=%s trade_no=%s reason=provider_mismatch actual_provider=%s client_ip=%s", model.PaymentProviderStripe, referenceId, topUp.PaymentProvider, callerIp))
return
}
if topUp.Status == common.TopUpStatusSuccess {
logger.LogInfo(ctx, fmt.Sprintf("Stripe callback idempotent success trade_no=%s client_ip=%s", referenceId, callerIp))
return
}
if topUp.Status != common.TopUpStatusPending {
logger.LogWarn(ctx, fmt.Sprintf("Stripe callback rejected provider=%s trade_no=%s reason=invalid_status status=%s client_ip=%s", model.PaymentProviderStripe, referenceId, topUp.Status, callerIp))
return
}
actualMinor, parseErr := strconv.ParseInt(event.GetObjectValue("amount_total"), 10, 64)
if parseErr != nil {
logger.LogWarn(ctx, fmt.Sprintf("Stripe callback rejected provider=%s trade_no=%s reason=invalid_amount_total client_ip=%s", model.PaymentProviderStripe, referenceId, callerIp))
return
}
expectedAmount := decimal.NewFromFloat(topUp.Money).Round(2)
actualAmount := decimal.NewFromInt(actualMinor).Div(decimal.NewFromInt(100)).Round(2)
if !expectedAmount.Equal(actualAmount) {
logPaymentReject(ctx, model.PaymentProviderStripe, referenceId, expectedAmount, actualAmount, "amount_mismatch", callerIp)
return
}
if strings.ToUpper(event.GetObjectValue("currency")) != "USD" {
logger.LogWarn(ctx, fmt.Sprintf("Stripe callback rejected provider=%s trade_no=%s reason=currency_mismatch expected_currency=%s actual_currency=%s client_ip=%s", model.PaymentProviderStripe, referenceId, "USD", strings.ToUpper(event.GetObjectValue("currency")), callerIp))
return
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e
rg -n --type=go 'StripePriceId|StripeUnitPrice|Stripe.*Currency|PaymentProviderStripe|currency|USD' controller setting model

Repository: QuantumNous/new-api

Length of output: 12683


Store or retrieve the expected Stripe currency per order instead of hardcoding USD.

The webhook at line 311 rejects any non-USD currency, but setting.StripePriceId (used in checkout creation at line 396) is configurable and can point to a Stripe Price in any currency. If a non-USD Price is configured, valid payments will be rejected. The codebase currently has no mechanism to persist or derive the expected currency; consider storing it with the order when the Stripe session is created.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@controller/topup_stripe.go` around lines 283 - 314, The webhook wrongly
hardcodes "USD" when validating currency; update the flow to store the expected
currency on the order when creating the Stripe checkout session (the code that
uses setting.StripePriceId) and then use that stored value in the callback
instead of "USD". Specifically: add/persist an expected currency field on the
TopUp record when creating the Stripe session (lookup the Price/currency or read
it from the created session in the checkout creation code), populate
topUp.Currency (or similar) there, and change the callback logic that currently
calls event.GetObjectValue("currency") and compares to "USD" to compare against
topUp.Currency (case-normalized) and log appropriately via logPaymentReject /
logger.LogWarn when mismatched. Ensure GetTopUpByTradeNo, topUp.PaymentProvider,
topUp.Status, and the amount checks remain unchanged.

Comment thread controller/topup.go
Comment on lines +373 to 403
if verifyInfo.TradeStatus == epay.StatusTradeSuccess {
topUp := model.GetTopUpByTradeNo(verifyInfo.ServiceTradeNo)
if topUp == nil {
logger.LogWarn(c.Request.Context(), fmt.Sprintf("Epay callback rejected provider=%s trade_no=%s reason=order_not_found client_ip=%s", model.PaymentProviderEpay, verifyInfo.ServiceTradeNo, c.ClientIP()))
_, _ = c.Writer.Write([]byte("fail"))
return
}
if topUp.PaymentProvider != model.PaymentProviderEpay {
logger.LogWarn(c.Request.Context(), fmt.Sprintf("Epay callback rejected provider=%s trade_no=%s reason=provider_mismatch actual_provider=%s client_ip=%s", model.PaymentProviderEpay, verifyInfo.ServiceTradeNo, topUp.PaymentProvider, c.ClientIP()))
_, _ = c.Writer.Write([]byte("fail"))
return
}
expectedAmount := normalizeMoneyDecimalFromFloat(topUp.Money)
actualAmount, amountErr := normalizeMoneyDecimalFromString(verifyInfo.Money)
if amountErr != nil {
logPaymentReject(c.Request.Context(), model.PaymentProviderEpay, verifyInfo.ServiceTradeNo, expectedAmount, decimal.Zero, "invalid_callback_amount", c.ClientIP())
_, _ = c.Writer.Write([]byte("fail"))
return
}
if !expectedAmount.Equal(actualAmount) {
logPaymentReject(c.Request.Context(), model.PaymentProviderEpay, verifyInfo.ServiceTradeNo, expectedAmount, actualAmount, "amount_mismatch", c.ClientIP())
_, _ = c.Writer.Write([]byte("fail"))
return
}
if topUp.Status != common.TopUpStatusPending && topUp.Status != common.TopUpStatusSuccess {
logger.LogWarn(c.Request.Context(), fmt.Sprintf("Epay callback rejected provider=%s trade_no=%s reason=invalid_status status=%s client_ip=%s", model.PaymentProviderEpay, verifyInfo.ServiceTradeNo, topUp.Status, c.ClientIP()))
_, _ = c.Writer.Write([]byte("fail"))
return
}
}
_, err := c.Writer.Write([]byte("success"))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Do not acknowledge Epay before the recharge path succeeds.

The handler writes "success" before the locked update/quota-credit block runs. If topUp.Update() or IncreaseUserQuota() fails afterward, the gateway has already been told the callback succeeded, so the paid order can remain uncredited with no retry signal.

Also applies to: 420-455

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@controller/topup.go` around lines 373 - 403, The handler currently writes
"success" before performing the critical post-payment operations, so move the
c.Writer.Write([]byte("success")) call to after the locked update/quota-credit
block (i.e., only after topUp.Update() and IncreaseUserQuota() succeed); if
either topUp.Update() or IncreaseUserQuota() fails, log the error (use
logger.LogError or existing logPaymentReject), write "fail" and return so the
gateway can retry. Locate code paths using GetTopUpByTradeNo,
normalizeMoneyDecimalFromFloat/FromString, logPaymentReject, and the subsequent
topUp.Update()/IncreaseUserQuota() calls and ensure acknowledgement is
conditional on their success. Ensure all early reject paths still write "fail"
immediately.

Comment thread controller/wechat.go
return
}
} else {
logger.LogWarn(c.Request.Context(), fmt.Sprintf("wechat auto register rejected provider=wechat reason=register_disabled wechat_id=%s client_ip=%s", wechatId, c.ClientIP()))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid logging raw wechat_id.

This is a stable external account identifier, so writing it verbatim to warn logs increases PII exposure. Prefer a hash/truncated form or log only internal request context.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@controller/wechat.go` at line 108, The warning log currently prints the raw
external account identifier wechatId in the logger.LogWarn call; update the code
that calls logger.LogWarn (the site using wechatId and c.ClientIP()) to avoid
logging raw PII by deriving and logging a non-reversible fingerprint (e.g., hash
like SHA256 and truncate to a short fixed length) or a truncated masked form of
wechatId instead, and keep c.ClientIP() as-is; ensure the new value replaces
wechatId in the fmt.Sprintf invocation so only the hashed/truncated/masked
identifier is written to logs.

Comment thread router/api-router.go
Comment on lines +39 to +44
apiRouter.POST("/oauth/email/bind", middleware.UserAuth(), middleware.CriticalRateLimit(), controller.EmailBind)
// Non-standard OAuth (WeChat, Telegram) - keep original routes
apiRouter.GET("/oauth/wechat", middleware.CriticalRateLimit(), controller.WeChatAuth)
apiRouter.POST("/oauth/wechat/bind", middleware.CriticalRateLimit(), controller.WeChatBind)
apiRouter.POST("/oauth/wechat/bind", middleware.UserAuth(), middleware.CriticalRateLimit(), controller.WeChatBind)
apiRouter.GET("/oauth/telegram/login", middleware.CriticalRateLimit(), controller.TelegramLogin)
apiRouter.GET("/oauth/telegram/bind", middleware.CriticalRateLimit(), controller.TelegramBind)
apiRouter.GET("/oauth/telegram/bind", middleware.UserAuth(), middleware.CriticalRateLimit(), controller.TelegramBind)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

These bind routes now admit access-token auth, but the handlers still depend on session state.

middleware.UserAuth() accepts Authorization-based auth, while controller.EmailBind, controller.WeChatBind, and controller.TelegramBind still do sessions.Default(c).Get("id").(int). An access-token-only request can now pass the middleware and then panic on the nil session lookup. Either switch those handlers to c.GetInt("id") or keep these routes behind a session-only guard.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@router/api-router.go` around lines 39 - 44, The bind routes now allow
Authorization header auth via middleware.UserAuth(), but the handlers EmailBind,
WeChatBind, and TelegramBind still read sessions.Default(c).Get("id").(int) and
will panic on access-token-only requests; update those handlers to safely read
the authenticated user id from the request context (use c.GetInt("id") or
equivalent context value set by UserAuth()) instead of casting session values,
or alternatively remove middleware.UserAuth() from these routes and enforce a
session-only guard so sessions.Default(c).Get("id") is always present; modify
either the middleware usage in router/api-router.go or the handlers (EmailBind,
WeChatBind, TelegramBind) accordingly to ensure no nil session lookup occurs.

@seefs001

Copy link
Copy Markdown
Collaborator

感谢您的贡献,您可以换个AI再扫描一下您的更改看有没有多余的操作或者破坏掉原有功能的。

@ll539

ll539 commented Apr 28, 2026

Copy link
Copy Markdown
Author

我已经重新过了一遍代码,并且做了对应的修改,我该怎么重新贡献呢?
这是我第一次贡献开源项目,不太了解流程,还请告知一下

@ll539 ll539 closed this Apr 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants