Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

Add a function that checks a Cloudflare Turnstile token on the server

未关闭 适合新手
#228 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

还没有人认领这个 Issue。

评估

难度
2/5
预计耗时
1-3 小时
新手友好度
88/100
Issue 类型
功能
描述清晰度
描述清楚
活跃度
活跃
技术栈
typescript
领域
backend, security

调研方向

阅读 packages/server/src/webhook.ts,了解现有的 fetch 超时模式;阅读 packages/server/tests/webhook-delivery.test.ts,了解 fetch 的模拟方式。实现 packages/server/src/security/turnstile.ts,并在 packages/server/tests/security/turnstile.test.ts 中添加指定的测试。满足验收标准后即为完成,包括请求字段、不匹配的情况,以及不会抛出异常或泄露 secret 的失败情况。

由索引模型根据 Issue 内容生成。

描述

enhancement hacktoberfest help wanted server

ChatCops is getting optional Cloudflare Turnstile checks: the widget gets a token from Turnstile when a visitor first opens the chat, and the server checks it before it starts a session. This issue is the server half of that check, as one small function in a new file. Wiring it into a route comes later, so this PR doesn't touch anything else.

What to do
Create packages/server/src/security/turnstile.ts with:

export interface TurnstileConfig {
  secretKey: string;
  /** The action set in the widget, if any. A token for another action is rejected. */
  action?: string;
  /** Hostnames the token may come from. Unset means any. */
  expectedHostnames?: string[];
  /** Default 5000. */
  timeoutMs?: number;
}

export type TurnstileResult =
  | { ok: true; hostname?: string; action?: string }
  | { ok: false; code: 'missing_token' | 'invalid_token' | 'hostname_mismatch' | 'action_mismatch' | 'unavailable'; errorCodes?: string[] };

export async function verifyTurnstile(
  token: string | undefined,
  config: TurnstileConfig,
  opts?: { remoteIp?: string; idempotencyKey?: string; fetch?: typeof fetch }
): Promise<TurnstileResult>;
  • POST to https://challenges.cloudflare.com/turnstile/v0/siteverify as described in Cloudflare's server-side validation docs, with secret, response, remoteip (when given) and idempotency_key (when given).
  • A token can only be redeemed once. The idempotency_key lets the server retry the same check after a network error without it failing as already used, so pass it through.
  • Return missing_token without calling the API when the token is empty, and unavailable when the request fails, times out (AbortSignal.timeout) or doesn't return JSON. Never throw.
  • Check hostname and action from the response against the config.
  • Use opts.fetch ?? globalThis.fetch, so tests can pass a fake. Don't import anything from Node; this has to run on Workers too.

Where to look

  • packages/server/src/webhook.ts has a similar fetch with a timeout
  • packages/server/tests/webhook-delivery.test.ts shows how the tests fake fetch

Acceptance criteria

  • New packages/server/src/security/turnstile.ts and packages/server/tests/security/turnstile.test.ts
  • Tests cover success, success: false with error codes, hostname and action mismatch, an empty token (no request sent), a network error, a timeout and a non-JSON reply
  • A test checks the request body, including idempotency_key and remoteip
  • The secret never appears in a returned value or in a log line
  • Not exported from @chatcops/server yet, and no changeset needed (pnpm changeset --empty)
  • pnpm test:coverage and pnpm lint pass

Want to work on this? Comment below and I'll assign it to you. Please take one issue at a time, branch off dev, and open your PR against dev with Closes #<this issue number>. Setup notes (pnpm, build before test) are in CONTRIBUTING.md.

主要语言
TypeScript
星标
13
派生
7
平均合并
4 小时 11 分钟
30 天内合并 PR
122

环境准备

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

codercops/chatcops 的其他 Issue

查看 codercops/chatcops 的全部 Issue

相似的 Issue

更多 TypeScript Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。