Skip to content

Add guest auth and enforce WS token identity#1

Merged
delete-cloud merged 5 commits into
masterfrom
experiment/game-rules-20260201
Feb 14, 2026
Merged

Add guest auth and enforce WS token identity#1
delete-cloud merged 5 commits into
masterfrom
experiment/game-rules-20260201

Conversation

@delete-cloud
Copy link
Copy Markdown
Collaborator

@delete-cloud delete-cloud commented Feb 11, 2026

Summary

  • add guest login API at /api/auth/guest/login and persist guest identities/sessions in existing auth tables
  • require Socket.IO auth token at connect time and derive vote identity from server-side token user_id
  • initialize guest auth on game page, pass token in WS handshake, and remove client-sent voterId from vote events
  • tighten review findings: phase update de-dup path, chase event deprecation note, configurable-threshold comments, guest deviceToken hardening
  • this branch also includes earlier n8n workflow/docs updates that were already present before the latest auth/ws fixes

Verification

  • cargo fmt -- --check
  • cargo test -p mimic-backend -- --nocapture
  • ./node_modules/.bin/tsc -p tsconfig.json --noEmit

新增游戏规则模块,引入房间阶段(active/voting/gameover)协议
扩展配置支持动态投票阈值、淘汰比例等游戏参数
在投票阶段禁止提交画作并添加倒计时广播
重构游戏结束条件检查以使用可配置规则
更新 n8n 工作流配置,引入分层重试策略(fast → quality → fallback)以提高可靠性和响应速度。
修改文档以说明新的配置选项和部署步骤。
Copilot AI review requested due to automatic review settings February 11, 2026 12:32
@delete-cloud
Copy link
Copy Markdown
Collaborator Author

@copilot 帮我review一下这次的改动是否合理

Copy link
Copy Markdown

Copilot AI commented Feb 11, 2026

@delete-cloud I've opened a new pull request, #2, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a guest-auth flow and enforces server-derived voter identity for Socket.IO votes, while also introducing server-driven room phase timing (active/voting/gameover) and configurable game/voting thresholds.

Changes:

  • Add guest login endpoint (/api/auth/guest/login) and persist guest identities/sessions in existing auth tables.
  • Require Socket.IO auth token at connect time; remove client-sent voterId and derive vote identity from the server-validated token user_id.
  • Add phase timing protocol (sync:state fields + phase:update) and new config-driven game rules/thresholds.

Reviewed changes

Copilot reviewed 19 out of 20 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
n8n-workflow.json Updates n8n workflow with fast→quality→fallback image generation and callbacks.
n8n-setup.md Documents updated n8n workflow setup and env-driven model/size tuning.
frontend/src/types/index.ts Removes voterId from generic vote payload typing.
frontend/src/types/battle.ts Removes voterId from vote event payload typings (front→back), keeps server→client voter fields.
frontend/src/lib/api.ts Adds guest login API + device/session identity helpers + localStorage token caching.
frontend/src/hooks/useWebSocket.ts Adds authToken to WS handshake auth; stops emitting client voterId.
frontend/src/hooks/useBattleSystem.ts Stops sending voterId in emitted vote events.
frontend/src/app/game/page.tsx Initializes guest auth on game page, passes WS auth token, sets player id from auth user id.
backend/src/ws/socketio_handler.rs Adds WS auth middleware, enforces authenticated vote identity, adds phase tick + phase update signaling, tweaks endgame logic.
backend/src/ws/mod.rs Exposes new game_rules module.
backend/src/ws/game_rules.rs Adds helper functions for ratio-based thresholds and AI overflow logic (with unit tests).
backend/src/services/auth.rs Adds guest-device login provider and session issuance; includes openid normalization + tests.
backend/src/routes/themes.rs Allows reusing rooms in active or voting status for a theme.
backend/src/routes/drawings.rs Rejects drawing submission during voting; uses config-driven vote threshold.
backend/src/routes/auth.rs Adds guest login request/response and route handler.
backend/src/models/room.rs Makes vote threshold configurable via Config.
backend/src/main.rs Registers Socket.IO namespace with auth middleware; adds guest login route.
backend/src/config.rs Adds env-configurable game/voting parameters and durations.
backend/WS_PHASE_PROTOCOL.md Documents WS phase protocol (sync:state, phase:update) and client countdown approach.
.gitignore Adds ignore entry for backend/ARCHITECTURE.md.
Comments suppressed due to low confidence (1)

backend/src/ws/socketio_handler.rs:388

  • check_game_end 的函数注释仍描述了已删除/变更的规则(例如 total_items<=5 的前置检查、固定阈值 3/5/5 等),但实现已经改为基于 game_rules 和配置比例计算。建议同步更新注释(或删除过期的规则说明),避免文档与行为不一致。
/// 检查游戏结束条件
///
/// 游戏结束条件:
/// 1. 前置检查: total_items <= 5 时不检查(还没有 AI 鱼出现)
/// 2. 失败条件: 杀了 3 条非 AI 鱼
/// 3. 失败条件: AI 鱼数量 > 5
/// 4. 胜利条件: AI 全灭 + 人类 >= 5
async fn check_game_end(socket: &SocketRef, state: &AppState, room: &Room) {

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 24 to +29
impl Room {
/// 计算动态投票阈值 (在线人数的 30%)
pub fn vote_threshold(&self) -> i32 {
let dynamic = ((self.online_count as f64) * 0.3).ceil() as i32;
std::cmp::max(4, dynamic)
pub fn vote_threshold(&self, config: &Config) -> i32 {
let ratio = config.vote_threshold_ratio.clamp(0.0, 1.0);
let dynamic = ((self.online_count as f64) * ratio).ceil() as i32;
std::cmp::max(config.vote_min_threshold, dynamic)
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

Room::vote_threshold 的注释仍写“在线人数的 30%”,但实现已改为从 Config.vote_threshold_ratio 读取(默认 0.6)。建议更新注释以反映实际阈值来源/默认值,避免后续误用或调参时产生误解。

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Updated in 62f7080: comment now reflects config-driven ratio/min-threshold behavior for vote threshold calculation.

Comment thread backend/src/ws/socketio_handler.rs Outdated
Comment on lines +779 to +784
check_game_end(socket, state, &room).await;
let refreshed: Room = sqlx::query_as("SELECT * FROM rooms WHERE id = $1")
.bind(room.id)
.fetch_one(&state.db)
.await
.ok()?;
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

check_game_end 里在将 room 置为 gameover 后会调用 emit_phase_update,但 phase_tick 在检测到 phase 变化时也会广播 phase:update。当投票超时触发 phase_tick 调用 check_game_end 时,这会导致重复的 phase:update(同一次状态切换 emit 两次)。建议统一由一个位置负责广播(例如移除 check_game_end 内的 emit,或让 check_game_end 返回是否已广播/更新后的 room 供 phase_tick 处理)。

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Updated in 62f7080: check_game_end now accepts a broadcast flag. phase_tick calls it with broadcast=false to avoid duplicate phase:update emissions on timeout transitions.

Comment thread backend/src/ws/socketio_handler.rs Outdated
Comment on lines 365 to 379
/// 追击 (重复投同目标,增加票数)
async fn on_vote_chase(
socket: SocketRef,
Data(data): Data<BattleVoteCastData>,
state: SioState<Arc<AppState>>,
) {
info!("[Socket.IO] Vote chase: {:?}", data);

// 检查游戏结束条件
check_game_end(&socket, &state, &room).await;
}
let payload = serde_json::json!({
"reason": "chase_disabled",
"fishId": data.fish_id
});
let _ = socket.emit("vote:error", &payload);
let _ = state;
}
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

vote:chase 当前被禁用但仍注册 handler,并通过 let _ = state; 来消除未使用变量告警。这会让协议层面表现为“支持该事件但永远报错”,且增加维护噪音。建议:要么移除 socket.on("vote:chase", ...) 注册/前端事件类型;要么保留但将 handler 签名改为不接收 state(或加 feature flag)并在协议文档中明确弃用。

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Updated in 62f7080: removed the unused state extractor from vote:chase handler, kept event registration for backward compatibility, and documented that chase is currently disabled with chase_disabled response.

Comment thread backend/src/services/auth.rs Outdated
Comment on lines +40 to +49
fn normalize_guest_openid(device_id: Option<&str>) -> String {
if let Some(device_id) = device_id {
let trimmed = device_id.trim();
if !trimmed.is_empty() {
return trimmed.chars().take(120).collect();
}
}

format!("guest:{}", Uuid::new_v4())
}
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

normalize_guest_openid 直接将客户端提供的 device_id 作为 openid(仅 trim/截断)。由于 device_id 并非秘密,攻击者可以伪造相同 device_id 来登录并获得同一 guest 用户身份,从而冒用投票身份。建议至少对 device_id 做服务端加盐哈希后再落库(保持稳定但不可被猜测/复用),或改为首次登录由服务端签发不可预测的 device token(客户端持久化该 token)。

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Updated in 62f7080: guest login now relies on server-issued random deviceToken identifiers (guest_device:UUID). Plain client-provided device_id values are no longer accepted as identity keys.

Comment thread n8n-workflow.json
Comment on lines +21 to +27
{
"parameters": {
"jsCode": "const input = $json;\n\nconst theme = input.theme || {};\nconst keywords = Array.isArray(theme.keywords) ? theme.keywords : [];\nconst palette = Array.isArray(theme.palette) ? theme.palette : [];\nconst promptStyle = typeof theme.prompt_style === 'string' ? theme.prompt_style : 'stylized illustration';\n\nconst keyword = keywords.length ? keywords[Math.floor(Math.random() * keywords.length)] : 'fish';\nconst colors = palette.slice(0, 3).join(', ');\n\nconst modelFast = process.env.ZENMUX_MODEL_FAST || 'nano banana pro';\nconst modelQuality = process.env.ZENMUX_MODEL_QUALITY || modelFast;\nconst modelFallback = process.env.ZENMUX_MODEL_FALLBACK || 'google/gemini-3-pro-image-preview';\n\nconst sizeFast = process.env.ZENMUX_SIZE_FAST || '256x256';\nconst sizeQuality = process.env.ZENMUX_SIZE_QUALITY || '512x512';\nconst sizeFallback = process.env.ZENMUX_SIZE_FALLBACK || sizeQuality;\n\nconst promptFast = `A ${promptStyle} of a ${keyword}. Simple clean background. High contrast, crisp silhouette. Colors: ${colors}. No text, no watermark, no logo.`;\nconst promptQuality = `A ${promptStyle} of a ${keyword}. Highly detailed but clean silhouette, crisp edges, soft shading. Simple background. Colors: ${colors}. No text, no watermark, no logo.`;\n\nconst name = keyword;\nconst description = `${promptStyle}`.slice(0, 60);\n\nreturn [{\n json: {\n ...input,\n keyword,\n name,\n description,\n model_fast: modelFast,\n model_quality: modelQuality,\n model_fallback: modelFallback,\n size_fast: sizeFast,\n size_quality: sizeQuality,\n size_fallback: sizeFallback,\n prompt_fast: promptFast,\n prompt_quality: promptQuality,\n }\n}];\n"
},
"id": "prepare",
"name": "Prepare",
"type": "n8n-nodes-base.code",
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

该 PR 标题/描述聚焦“guest auth + WS token identity”,但这里引入了较大幅度的 n8n workflow 变更(新的 fast/quality/fallback 分支、Zenmux endpoint 等),PR 描述未提及。建议在 PR 描述中补充该变更的动机/影响与验证方式,或将 workflow 调整拆分到独立 PR,便于回溯与风险评估。

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Updated PR description to call out the pre-existing n8n workflow/docs changes on this branch and their scope relative to the auth/ws fixes.

@delete-cloud
Copy link
Copy Markdown
Collaborator Author

@copilot please re-review the latest commit 62f7080 (addressed all previous inline findings).

Copy link
Copy Markdown

Copilot AI commented Feb 11, 2026

@delete-cloud I've opened a new pull request, #3, to work on those changes. Once the pull request is ready, I'll request review from you.

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.

3 participants