Skip to content

sync: dev to extern-contrib - #1020

Merged
boomzero merged 13 commits into
extern-contribfrom
dev
Aug 23, 2026
Merged

sync: dev to extern-contrib#1020
boomzero merged 13 commits into
extern-contribfrom
dev

Conversation

@github-actions

@github-actions github-actions Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

sync-branches: New code has just landed in dev, so let's bring extern-contrib up to speed!

Summary by Sourcery

Improve submission reliability during busy judge queues by adding robust captcha handling and local recognition.

New Features:

  • Add optional local recognition and manual entry support for XMOJ submission captchas, including refresh and fallback handling.

Bug Fixes:

  • Ensure captcha requirements are detected and enforced consistently when the judge queue state changes during submission.

Enhancements:

  • Centralize default-off setting behavior for debugging and interface replacement options.

Build:

  • Bump the userscript and package versions to 3.6.4.

Summary by cubic

Show and submit the server captcha on the custom submit page to prevent silent failures when the judge queue is busy. Previously the page dropped the vcode field; now it renders the captcha, includes vcode in POSTs, and blocks blank submissions.

  • Submit page mirrors the server captcha before DOM replacement, shows an image and input, refreshes on click, and expands the captcha area on “验证码错误”.
  • Always sends vcode; safe when the queue is idle because submit.php ignores the field.
  • Blocks “强制提交” if captcha is missing to avoid server vfail upgrading to 8‑char challenges.
  • Adds AutoCaptcha (default on): local, 4‑digit recognition that only fills when confident; otherwise leaves the field for manual entry.
  • Centralizes defaults via DefaultOffSettings; bumps version to 3.6.4 in package.json and updates release notes in Update.json.

Written for commit 8e9b445. Summary will update on new commits.

Review in cubic

boomzero and others added 13 commits August 23, 2026 10:56
评测队列繁忙时 XMOJ 会启用 vcode.php 图片验证码,但提交界面是脚本自己
渲染的,服务端的验证码字段在替换 DOM 时被丢弃,提交因此静默失败。

- 替换页面前先检测服务端是否渲染了验证码字段,若有则在提交按钮上方
  显示验证码图片与输入框,点击图片可更换
- 提交时附带 vcode 参数;队列不繁忙时 submit.php 会忽略该字段,因此
  无条件携带是安全的
- submitpage.php 在队列 >10 时显示验证码,submit.php 在 >50 时才校验,
  两者可能不一致:识别到"验证码错误"时展开验证码区域并允许重新提交
- 验证码为空时在客户端拦截。提交空验证码会让服务端标记 vfail,此后
  验证码会从 4 位数字变成 8 位字母数字,直到会话结束
- 新增 AutoCaptcha 开关,通过 captchaSolve 自动识别 4 位数字验证码;
  识别结果非 4 位数字时不填入,8 位字母验证码不送识别,均可手动填写

Closes #420

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
实测 Workers AI 的视觉模型都读不准 XMOJ 的验证码:以 7602 为例,
llava-1.5-7b 返回 600,llama-4-scout 返回 1834,mistral-small-3.1
返回 1234;另一张 7908 的图 llava 返回 9990。

四位数字的错误答案会通过校验被提交,失败后服务端置 vfail,验证码从
4 位数字升级为 8 位字母数字,直到会话结束,比留空更糟。因此把
AutoCaptcha 改为默认关闭,仅作为实验性功能保留接口。

顺带把默认关闭项提取为 DefaultOffSettings,供 UtilityEnabled 与设置
列表共用——两处都会给缺失的项写入默认值,不一致时先执行的一方说了算。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
vcode.php 用 imagettftext(15px, Vera.ttf) 在固定位置绘制 4 位数字,
每个字形在不同验证码之间逐像素相同,因此模板匹配可以直接读出来,
不需要把图片发给任何模型。

背景是一种随机色,文字是它的反色,噪点是第三种随机色:取出现次数
最多的颜色作为背景即可定位文字颜色。跳过 1 像素黑边,否则接近白色
的背景会让黑边被当成文字。切分出的字形与 10 个模板逐一比对,除了
奖励命中的笔画,也惩罚模板之外的墨点——否则带噪点的 0 会和 9 打平。

只有切出恰好 4 个字形、且每个字形的最佳得分领先第二名 4 分以上时
才填入,否则留空由用户填写:错误答案会触发 vfail,把验证码升级成
8 位字母数字,比留空更糟。

实测 300 张生成样本 227 正确 0 错误,40 张真实验证码填入 31 张,
14 张人工标注样本 13 正确 1 放弃 0 错误。因为不会填错,AutoCaptcha
恢复默认开启,同时移除 captchaSolve 依赖与相关 @connect。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
验证码为空的拦截原来只在"提交"的处理函数里。检查未通过时页面会留下
"强制提交"按钮,而真正发出请求的是它:这段时间里用户可以点击验证码
图片换一张(会清空输入框)或手动清空,再点"强制提交"就会带着空验证码
发出请求,触发本要避免的 vfail 升级。

把拦截提取为 CaptchaIsMissing,在实际发出请求的 PassCheck 处理函数
开头也调用一次,并在拦截时重新隐藏"强制提交"按钮。

Reported-by: chatgpt-codex-connector
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@sourcery-ai

sourcery-ai Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Implements local image-based solving for XMOJ’s vcode captcha on the submit page, wires it into the submission flow with safety checks, refactors default-off settings into a shared constant, and bumps the script/package versions to 3.6.4.

Sequence diagram for captcha-aware code submission

sequenceDiagram
    participant User
    participant SubmitPage
    participant Captcha as vcode.php
    participant Submit as submit.php

    SubmitPage->>SubmitPage: NativeCaptchaShown
    alt captcha is shown
        SubmitPage->>Captcha: fetch("vcode.php?" + Math.random())
        Captcha-->>SubmitPage: ImageBlob
        SubmitPage->>SubmitPage: GetCaptchaLength(ImageBlob)
        alt four-digit captcha and AutoCaptcha enabled
            SubmitPage->>SubmitPage: SolveCaptcha(ImageBlob)
            SubmitPage->>SubmitPage: Fill #vcode when confidence is sufficient
        else unsupported or uncertain captcha
            SubmitPage-->>User: Request manual input
        end
    end
    User->>SubmitPage: PassCheck.click
    SubmitPage->>SubmitPage: CaptchaIsMissing()
    alt captcha missing
        SubmitPage-->>User: Show captcha-required error
    else captcha available
        SubmitPage->>Submit: POST submission with GetCaptchaParameter()
        alt captcha rejected
            Submit-->>SubmitPage: Response containing 验证码错误
            SubmitPage->>SubmitPage: RefreshCaptcha("")
            SubmitPage-->>User: Show retry message
        else accepted
            Submit-->>SubmitPage: Submission response or redirect
        end
    end
Loading

File-Level Changes

Change Details Files
Add local captcha recognition and UI integration to the submit page, including robust handling of when the server requires or rejects captcha answers.
  • Detect when the native captcha is present on submitpage.php and keep that state across the custom submit UI
  • Render a captcha input/image/status block in the custom submit UI and show it only when needed
  • Ensure the captcha image is fetched exactly once per challenge and reused so that the displayed image matches the server’s expected answer
  • Add logic to read the GIF header to infer captcha length and distinguish 4-digit numeric captchas from 8-character alphanumeric ones
  • Build a pixel mask from the captcha image by separating background from text via colour inversion and tolerances
  • Split the mask into digit glyph columns and match each against precomputed Vera.ttf glyph bitmaps
  • Use a score + margin system to only accept unambiguous matches and fall back to manual entry otherwise
  • Gate automatic solving behind a new AutoCaptcha setting and never overwrite user-typed captcha values
  • Add event handlers: clicking the image refreshes the captcha; Enter in the captcha field triggers submission
  • Require a non-empty captcha when it’s shown before both PassCheck and the main submit flows, surfacing clear error messages and focusing the field
  • Append the captcha value to submit.php POST bodies when present, and on captcha failures, refresh the challenge and show a specific error prompting re-entry
XMOJ.user.js
Introduce and reuse a shared list of settings that default to off, and add the AutoCaptcha option to the settings UI.
  • Define DefaultOffSettings constant listing settings that should default to false in localStorage
  • Update UtilityEnabled to seed missing setting values based on DefaultOffSettings instead of a local hard-coded array
  • Update settings UI initialization to seed each setting’s default from DefaultOffSettings rather than always true
  • Add a new AutoCaptcha setting entry in the settings menu, enabling users to toggle automatic captcha recognition
XMOJ.user.js
Bump project and userscript versions to 3.6.4 to reflect the new functionality.
  • Update @Version metadata in the userscript header from 3.6.3 to 3.6.4
  • Update package.json version field from 3.6.3 to 3.6.4
XMOJ.user.js
package.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying xmoj-script-dev-channel with  Cloudflare Pages  Cloudflare Pages

Latest commit: 8e9b445
Status: ✅  Deploy successful!
Preview URL: https://55fc6201.xmoj-script-dev-channel.pages.dev

View logs

@sourcery-ai sourcery-ai 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.

Hey - I've reviewed your changes and they look great!

Sourcery assessment

Needs a human reviewer. The change alters captcha enforcement and automatically submits locally recognized answers, so a parsing or session-state mistake could consume captcha attempts, escalate the challenge, or cause submissions to be rejected or mishandled. Reverting stops the behavior but cannot undo failed captcha attempts or submissions already made.


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@boomzero
boomzero merged commit b14b245 into extern-contrib Aug 23, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant