Skip to content

修改数据看板文字 - #51

Merged
Calcium-Ion merged 1 commit into
QuantumNous:mainfrom
wxDadadada:main
Jan 17, 2024
Merged

修改数据看板文字#51
Calcium-Ion merged 1 commit into
QuantumNous:mainfrom
wxDadadada:main

Conversation

@wxDadadada

Copy link
Copy Markdown
Contributor

修改数据看板文字

@wxDadadada wxDadadada changed the title Update SiderBar.js 修改数据看板文字 Jan 17, 2024
@Calcium-Ion

Copy link
Copy Markdown
Member

谢谢😘

@Calcium-Ion
Calcium-Ion merged commit 3a8be50 into QuantumNous:main Jan 17, 2024
sususu98 pushed a commit to sususu98/new-api that referenced this pull request Dec 1, 2025
* fix: 修复 Session 数据越权访问漏洞, close QuantumNous#51

## 问题描述
普通用户(非管理员令牌)登录 Web UI 后,可以通过"仪表盘" → "活跃 Session"
查看到其他用户 5 分钟内的请求内容和响应内容,造成严重的数据泄露。

## 安全影响
- **数据泄露风险**: 用户可以查看其他用户的敏感请求和响应
- **隐私侵犯**: 违反用户数据隔离原则
- **合规风险**: 可能违反数据保护法规(如 GDPR)

## 修复方案
在所有 Session 相关 API 中添加用户权限检查:

1. **getActiveSessions()** - 列表过滤
   - 管理员:可查看所有用户的 Session
   - 普通用户:只能查看自己的 Session

2. **getAllSessions()** - 列表过滤
   - 同上,支持活跃和非活跃 Session

3. **getSessionDetails()** - 详情访问控制
   - 检查 Session 所有权
   - 非所有者尝试访问时记录安全日志并拒绝

4. **getSessionMessages()** - 消息访问控制
   - 检查 Session 所有权
   - 记录越权访问尝试

5. **getSessionResponse()** - 响应体访问控制
   - 检查 Session 所有权
   - 记录越权访问尝试

## 技术实现
- 使用 `getSession()` 获取当前登录用户
- 通过 `aggregateSessionStats()` 查询 Session 的 userId
- 比对 `sessionStats.userId` 与 `currentUserId`
- 所有越权访问尝试都会记录安全日志

## 测试建议
1. 创建两个普通用户(user1, user2)
2. user1 发起 API 请求产生 Session
3. user2 登录 Web UI 尝试查看 user1 的 Session
4. 预期结果:user2 只能看到自己的 Session,无法看到 user1 的

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Code Bot <bot@claude.ai>
Co-authored-by: Claude <noreply@anthropic.com>
x22x22 pushed a commit to x22x22/new-api that referenced this pull request Apr 24, 2026
x22x22 pushed a commit to x22x22/new-api that referenced this pull request Apr 24, 2026
x22x22 pushed a commit to x22x22/new-api that referenced this pull request Apr 24, 2026
haojianggod pushed a commit to Hermerz/new-api that referenced this pull request May 23, 2026
Three-prong refinement of QuantumNous#51 Phase 1 UserGroupModelDiscount layer based
on BD UX feedback + @wswuai's design review (Hermerz/Hermes#66):

1. Semantic (option A): discount value = customer's final fraction of
   model official price. When set, bypass GroupRatio entirely so BD's
   "0.2" input = customer pays 2折 of official directly (no need to
   reverse-engineer GroupRatio).

2. Log observability: PriceData gains UserGroupDiscount field;
   GenerateTextOtherInfo writes user_group_discount to log when
   configured. All wrappers (Text/Wss/Audio/Claude) pick it up via
   relayInfo.PriceData with no signature changes.

3. UI clarity: UserGroupModelDiscountSettings extraText updated.

Lookup key stays info.UserGroup (= user.Group, the customer's home tier)
per QuantumNous#51 spec — "客户分层 × 模型" is a user-tier concern, not a token-key
concern. QuantumNous#51 explicitly punts "单 key 级别折扣覆盖" out of scope. See
decision record in Hermerz/Hermes#66.

Also fixes a pre-existing WSS bug surfaced by Codex cross-model review:
PreWssConsumeQuota now syncs PriceData.ModelRatio + GroupRatio back to
relayInfo so PostWssConsumeQuota settle uses the same values as
pre-consume (avoids divergence when autoGroup re-routes mid-session).

Follow-ups (non-blocking, separate issues):
- Hermerz/Hermes#67: extract applyUserGroupDiscount helper (de-dup
  the discount apply logic between price.go and quota.go)
- Hermerz/Hermes#68: lift discount into PriceData.Discount + apply at
  settle time for billing observability

Reviewed by /god-pr-self-review + Codex Tier 1 cross-model (2 rounds).

Refs: Hermerz/Hermes#51, Hermerz/Hermes#66

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
haojianggod pushed a commit to Hermerz/new-api that referenced this pull request May 23, 2026
QuantumNous#68 no-bake refactor + QuantumNous#67 LookupUserGroupDiscount helper for the
UserGroupModelDiscount layer (QuantumNous#51 Phase 1 option A).

Before (commit 472571c):
  ModelPriceHelper baked discount into modelRatio + forced
  GroupRatio=1.0 at pre-consume. PriceData.ModelRatio = baked value,
  GroupRatio = 1.0 for matched requests. Log model_ratio + group_ratio
  fields lost the "市场基线 vs 客户分层 vs 折扣" decomposition needed
  for 对账.

After (this commit):
  ModelPriceHelper captures discount RAW into priceData.UserGroupDiscount
  + leaves ModelRatio + GroupRatio raw. New PriceData.EffectiveGroupRatio()
  method returns UserGroupDiscount if > 0 else raw GroupRatio. Settle
  paths (text_quota.go calculateTextQuotaSummary, quota.go PostWss/
  PostAudio) use Effective for billing math but pass raw values to log
  writer. Log gains effective_model_ratio derived field.

Math identical: discount=0.2 + GroupRatio=0.37 + ModelRatio=0.625 →
final ratio = 0.125 (= 0.625 × 0.2) both before and after. Option A
"discount bypasses GroupRatio" semantic preserved.

Files:
- types/price_data.go: + EffectiveGroupRatio() method, doc updates
- relay/helper/price.go: no-bake; uses LookupUserGroupDiscount helper
- service/quota.go: PreWss no-bake + sync; PostWss/Audio split
  effectiveGroupRatio (billing) vs rawGroupRatio (log)
- service/text_quota.go: summary.UserGroupDiscount field; dGroupRatio
  derived as effective (used in ~9 multiplications)
- service/log_info_generate.go: + effective_model_ratio log field
- setting/ratio_setting/user_group_discount.go: + LookupUserGroupDiscount
  helper (QuantumNous#67) with sentinel-0 constraint doc

Constraint: BD must not configure discount = 0 — silently treated as
"not configured" due to sentinel-0 collision. Admin UI validation
filed as Hermerz/Hermes#71.

Reviewed by /god-pr-self-review + Codex Tier 1 cross-model.
Codex flagged 2 Criticals:
  - C1 (EffectiveGroupRatio drops GroupRatio): rejected as
    hallucinated diff (Codex referenced BuildPriceData /
    EffectiveInputRatio functions that don't exist in this codebase;
    invented modelRatio*groupRatio*discount formula). Verified actual
    472571c commit baked modelRatio*discount with GroupRatio=1.0
    bypass, identical to current EffectiveGroupRatio semantic.
  - C2 (sentinel-0 collision): in-scope, addressed via doc warning
    + follow-up issue.

Refs: Hermerz/Hermes#51, QuantumNous#66, QuantumNous#67, QuantumNous#68
Follow-up: Hermerz/Hermes#71 (admin UI validation)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
lingozhi pushed a commit to lingozhi/new-api that referenced this pull request Jul 17, 2026
Measured over 262 prod requests, all six channels serving the SAME model at the
SAME reasoning effort — so the spread is the channel, not the request:

  #41 1275ms (n=90)   QuantumNous#51 1328ms (n=66)   QuantumNous#42 2337ms (n=17)
  #33 3388ms (n=24)   QuantumNous#45 3537ms (n=52)   QuantumNous#57 8133ms (n=8)

Bucketing by uncached prompt tokens holds p50 flat (1612/1934/2073/1802 for
0-2k/2-6k/6-20k/20k+), which rules out prefill volume as the cause. Meanwhile
~100% of requests are affinity-pinned, so the health-weighted selection that was
supposed to steer around slow channels almost never runs — the only exit is
IsChannelFastEnoughForAffinity, and `score > 0.1` with `score = 1/(1+latency)`
only fires past 9s. QuantumNous#45 and QuantumNous#57 kept their sticky traffic forever; 33% of
requests were pinned to a channel 2.6x+ slower than the one next to it.

Release relative to the best peer for the same model+path instead: leave only
when the sticky is BOTH slower than 2s absolute and >2x that peer. The absolute
floor stops churn over gaps nobody can feel (0.3s vs 0.15s is 2x), the ratio
stops churn for gains too small to repay a migration. QuantumNous#42 at 1.83x stays.

The reason this could not just be turned on: migration causes a cold prompt
cache by construction, and a cold 240k-token prefill measured 23348ms. That one
number breaks two mechanisms at once, both of which then punish the channel we
just chose *for being the fastest*:

  - the latency EWMA, which is shared by every affinity key on the channel, so
    one migration would make the destination look slow to all of them and
    stampede them off it, each paying its own cold prefill;
  - cooldownSlowChannelIfNeeded, an entirely separate path that yanks a channel
    out of rotation for 30 minutes past 30s FRT — 23.3s is 78% of that.

So the release is gated three ways. ColdCacheStart marks the attempt and keeps
its latency out of both mechanisms (failures still count — a cold start is no
excuse for erroring). A per-key cooldown stops one key bouncing. A global
minimum interval drains a slow channel one key at a time, because the slow
verdict is per-channel: without it every key pinned to QuantumNous#45 leaves on the same
tick and their cold prefills land on #41 together, making it genuinely slow —
a cascade no latency-exclusion can prevent, since that load is real.

Circuit-open releases stay unconditional and never reach AcquireChannelHealth,
or a rate-limited key would be parked on a tripped channel and a paying request
would become its half-open probe.

Accepted: weighted re-selection can hand a released key back to the same slow
channel (~12.5% by weight). Not excluded — that risks a 503, and the cache
there is still warm, so the only cost is the 10-minute slot.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
lingozhi pushed a commit to lingozhi/new-api that referenced this pull request Jul 17, 2026
Prod, one bad hour: four Codex sessions, one (1ff18e9d) sat on an idle #17 doing
1-2s the whole time, while another (c34a4d35) churned QuantumNous#51 -> #41 -> QuantumNous#56, every
request 8-22s, never once landing on #17. The first-token times the user saw
(6-11s) were these bounced sessions.

When a session is released from a slow channel (affinity migration, or its
sticky channel cooling), it re-picks via weighted-random selection. The health
score weighting there under-separates fast from slow: score = 1/(1+EWMA), so 12s
vs 1.8s is only ~4.6x. With several slow channels their combined weight rivals
the one fast channel, and the bounced session is dropped back onto a slow one
about as often as not. That is how c34a4d35 stayed slow.

Multiply the selection weight of a channel measured fast right now (EWMA <
affinityFastLatency) by 8. A single fast channel then takes ~80-90% of re-picks
against a handful of slow peers instead of ~59%, so a bounced session lands on
it. It self-limits: the boost keys off the live EWMA, so if the fast channel
slows under the added load past the threshold it stops being boosted and traffic
redistributes; slow channels keep a small share, which probes them for recovery.
When nothing is under the threshold (whole fleet slow) no channel is boosted and
selection falls back to plain health weighting — the same "only move toward
somewhere genuinely fast" rule the affinity migration logic uses.

Both selection paths (memory-cache and DB) now share EffectiveSelectionWeight so
they weight identically; previously only one would have been changed.

Note this composes with the existing slow-circuit trip (a channel past
CHANNEL_HEALTH_SLOW_LATENCY, 9s, is dropped from selection outright): the boost
governs the still-selectable 2-9s band and whatever remains after trips.

Tests fail when the boost is removed: the fast channel's share falls from >0.8
to ~0.59.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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