feat(paypal-flow): 添加邮箱输入框重填功能

This commit is contained in:
QLHazyCoder
2026-04-28 15:31:59 +08:00
parent 87fc333848
commit 2d1bad3642
7 changed files with 262 additions and 18 deletions
+16 -8
View File
@@ -227,6 +227,18 @@ function getPayPalLoginPhase(emailInput, passwordInput) {
return '';
}
function refillPayPalEmailInput(emailInput, email) {
if (!emailInput) return;
if (typeof emailInput.focus === 'function') {
emailInput.focus();
}
fillInput(emailInput, '');
fillInput(emailInput, email);
if (typeof emailInput.blur === 'function') {
emailInput.blur();
}
}
async function submitPayPalLogin(payload = {}) {
await waitForDocumentComplete();
@@ -241,9 +253,7 @@ async function submitPayPalLogin(payload = {}) {
const emailNextButton = findEmailNextButton();
if (emailInput && emailNextButton && isEnabledControl(emailNextButton) && (!passwordInput || !findPasswordLoginButton())) {
if (normalizeText(emailInput.value || '') !== email) {
fillInput(emailInput, email);
}
refillPayPalEmailInput(emailInput, email);
simulateClick(emailNextButton);
return {
submitted: false,
@@ -253,9 +263,7 @@ async function submitPayPalLogin(payload = {}) {
}
if (!passwordInput && emailInput && email) {
if (normalizeText(emailInput.value || '') !== email) {
fillInput(emailInput, email);
}
refillPayPalEmailInput(emailInput, email);
const nextButton = await waitUntil(() => {
const button = findEmailNextButton() || findLoginNextButton();
return button && isEnabledControl(button) ? button : null;
@@ -272,8 +280,8 @@ async function submitPayPalLogin(payload = {}) {
};
} else if (!passwordInput && emailInput && !email) {
throw new Error('PayPal 账号为空,请先在侧边栏配置。');
} else if (emailInput && email && normalizeText(emailInput.value || '') !== email) {
fillInput(emailInput, email);
} else if (emailInput && email) {
refillPayPalEmailInput(emailInput, email);
}
passwordInput = passwordInput || await waitUntil(() => findPasswordInput(), {
+132 -4
View File
@@ -1,6 +1,6 @@
# Codex 注册扩展相关项目、更新、邮箱、PayPal 与 Clash Verge 配置教程
本教程用于说明相关项目地址、扩展更新方式、`Cloudflare Temp Email``iCloud 隐私邮箱``QQ 邮箱` 的使用方法、`PayPal` 注册绑卡流程、节点检测与纯净度检查,以及 [Clash Verge](https://github.com/clash-verge-rev/clash-verge-rev) 的 `🔁 非港轮询` 配置方法。
本教程用于说明相关项目地址、扩展更新方式、`Cloudflare Temp Email``iCloud 隐私邮箱``QQ 邮箱` 的使用方法、`PayPal` 注册绑卡流程、扩展内置动态 IP 代理、节点检测与纯净度检查,以及 [Clash Verge](https://github.com/clash-verge-rev/clash-verge-rev) 的 `🔁 非港轮询` 配置方法。
## 适用场景
@@ -11,6 +11,7 @@
- 需要临时切换 `QQ 邮箱` 地址继续使用
- 需要使用 `网易邮箱``网易邮箱大师` 注册多个邮箱或替身邮箱
- 需要注册并使用 `PayPal` 个人账户
- 需要在扩展内使用 `711Proxy` 动态 IP,并在自动流程中按轮次切换出口
- 需要检查当前节点的出口 IP、纯净度、泄露情况和访问速度
- 需要在 `Clash Verge` 中启用 `🔁 非港轮询`
@@ -26,6 +27,7 @@
- 手机端已安装 `网易邮箱``网易邮箱大师`
- 一个可正常接收短信的手机号
- 一张可在线支付的借记卡或信用卡
- 如需使用扩展内置动态 IP,需准备 `711Proxy` 的 Host、Port、代理账号和代理密码
- 如需部署 `cpa`,部署环境必须可以访问 `OpenAI`
- 已安装 [Clash Verge](https://github.com/clash-verge-rev/clash-verge-rev),并已导入可用订阅
@@ -426,7 +428,113 @@
- **PayPal 登录后页面无法继续跳转**
稍等片刻让页面加载完毕。如果长时间未响应,检查浏览器是否有弹窗被隐藏,或尝试刷新页面。
### 第九部分:节点检测与纯净度检查网站
### 第九部分:扩展内置动态 IP 代理使用教程
本部分说明扩展侧边栏里的 `IP代理` 功能。
它和 [Clash Verge](https://github.com/clash-verge-rev/clash-verge-rev) 这类系统代理不一样:扩展会通过浏览器代理 API 给当前浏览器设置 PAC 代理,并自动回填代理鉴权。当前首版只开放 `711Proxy` 的账号密码模式,`API 拉取` 和多账号列表入口暂未开放。
#### 一、什么时候需要打开 `IP代理`
如果你已经在 [Clash Verge](https://github.com/clash-verge-rev/clash-verge-rev) 或其他客户端里稳定使用节点,可以继续使用外部代理。
如果你希望在扩展里直接控制动态 IP、检查当前出口、按成功轮次自动切换,或者不想依赖系统全局代理,就使用这里的 `IP代理`
开启 `IP代理` 后,扩展会接管浏览器代理。
关闭 `IP代理` 后,浏览器会恢复默认代理或外部全局代理。
#### 二、注册或登录 `711Proxy`
在侧边栏打开 `IP代理` 后,`代理服务` 当前固定为 `711Proxy(首版)`
点击旁边的 `注册` 按钮,按页面提示完成注册或登录。
在网站中完成注册、登录和套餐准备后,进入代理信息页面,找到可用于账号密码代理的 `Host``Port``Username``Password`
#### 三、填写固定账号代理
1. 在扩展侧边栏打开 `IP代理` 开关。
2. `代理模式` 保持 `账号密码`
3. 填写 `代理 Host`,例如 `global.rotgb.711proxy.com`
4. 填写 `代理 Port`,例如 `10000`
5. `代理协议` 一般保持 `HTTP`,除非你的代理信息明确要求 `HTTPS``SOCKS5``SOCKS4`
6. 填写 `代理账号``代理密码`
7. 按需填写 `地区参数`,例如 `US``DE``HK`
8. 按需填写 `会话(session)``时长(life)`
`地区参数` 只接受两个字母的国家或地区代码。
`会话(session)` 会被追加或写回到用户名里的 `session-xxxx`
`时长(life)` 会被追加或写回到用户名里的 `sessTime-xx`711Proxy 的有效范围按 `5-180` 分钟使用更稳。
如果你的 `711Proxy` 用户名里已经带了 `region-US``session-xxxx``sessTime-30`,扩展会优先识别用户名里的值。
如果你在表单里修改地区、session 或时长,扩展会把它们同步回最终生效的代理用户名。
#### 四、同步、下一条、Change 和检测出口
填写或修改代理信息后,不要只保存后就直接开跑。建议按下面顺序操作:
1. 点击 `同步`
扩展会保存当前配置,生成代理规则,应用到浏览器,并自动做一次出口检测。
这是修改 Host、Port、账号、密码、地区、session 或时长后最常用的按钮。
2. 查看 `代理状态`
状态卡会显示当前代理、当前出口 IP、出口地区和诊断详情。
如果显示 `当前代理``当前出口`,说明扩展已经能看到代理出口。
3. 点击 `检测出口`
它只重新检测当前出口,不主动更换节点。
如果你怀疑检测结果没刷新,或者刚刚切换过外部网络,可以点它复测。
4. 点击 `检查IP`
它会打开 `https://ipinfo.io/what-is-my-ip`,用于人工确认网页看到的公网 IP。
5. 点击 `下一条`
当前首版主要是固定账号模式。如果只有一条可用代理,`下一条` 会重绑当前节点并复测,不保证一定换出口。
如果后续开放多账号列表或 API 池,`下一条` 才会真正切到池里的下一条。
6. 点击 `Change`
`Change` 只支持 `711Proxy + 账号密码模式 + 用户名包含 session` 的场景。
它会保持当前 session,强制重绑代理链路并刷新出口,适合想换出口但不想改整条账号配置时使用。
#### 五、任务切换阈值
`任务切换阈值` 表示自动流程成功多少轮后尝试自动切换一次代理。
默认是 `20` 轮,可填写 `1-500`
需要注意:
- 当前只有一条固定账号时,即使命中阈值,也会跳过自动切换。
- 如果后续有多条可切换代理,命中阈值后会自动执行 `下一条`
- 这个阈值只影响自动流程成功后的切换节奏,不会替代你手动点击 `同步``检测出口`
#### 六、状态卡怎么看
常见状态含义如下:
- `未开启`:扩展没有接管浏览器代理,继续使用默认网络或外部全局代理。
- `当前代理:host:port;当前出口:x.x.x.x`:代理已经应用,并检测到出口 IP。
- `已启用,但账号模式没有可用代理`:Host/Port 为空或格式不完整,需要先补齐代理信息。
- `连通性失败`:代理应用了,但没有检测到可用出口,优先检查 Host、Port、协议、账号和密码。
- `地区校验未通过`:检测到的出口地区和你填写的地区参数不一致。711Proxy 场景下扩展会保留接管并给出警告,你需要决定是否继续使用这个出口。
- `当前链路未收到 407 代理鉴权挑战`:代理服务没有按浏览器扩展代理 API 预期返回标准鉴权挑战,可能导致账号密码无法自动回填。可以尝试 `Change`、关闭再开启 `IP代理`、换 session,或者更换代理节点。
如果代理不可用,扩展会启用目标站点阻断保护,避免在代理失效时继续直连访问目标站点。修好代理后重新点击 `同步``检测出口` 即可恢复。
#### 七、推荐使用顺序
首次配置建议按这个顺序:
1. 点击 `注册` 打开 `711Proxy`,准备代理账号信息。
2. 打开扩展侧边栏的 `IP代理`
3. 填写 Host、Port、协议、账号、密码。
4. 填写地区参数,例如 `US`
5. 填写 session 和时长,例如 session 为随机前缀、时长为 `30`
6. 点击 `同步`
7. 确认 `代理状态` 里有出口 IP。
8. 点击 `检查IP`,人工确认网页检测结果。
9. 再继续执行注册、登录或自动流程。
如果后续要换出口,优先尝试 `Change`
如果 `Change` 不可用,再调整 session 或代理账号后点击 `同步`
### 第十部分:节点检测与纯净度检查网站
本部分用于检查当前代理节点的出口 IP、归属地、风险标签、泄露情况和网站访问速度。
建议每次切换节点后都重新打开这些网站检查一次。
@@ -460,7 +568,7 @@
接着打开 [IPPure](https://ippure.com/) 检查纯净度、黑名单、代理识别和泄露情况。
最后用 [TCPTest 网站测速](https://www.tcptest.cn/?cckey=e62f31db) 测试目标网站的访问速度和连通性。
### 第十部分:配置 [Clash Verge](https://github.com/clash-verge-rev/clash-verge-rev) 的 `🔁 非港轮询`
### 第十部分:配置 [Clash Verge](https://github.com/clash-verge-rev/clash-verge-rev) 的 `🔁 非港轮询`
#### 第一步:添加扩展脚本
@@ -569,7 +677,7 @@ function main(config, profileName) {
5. 确认左侧 `设置` 中的 `系统代理``System Proxy`)已经开启。
![2026 04 25 003703](https://apikey.qzz.io/content-assets/library/2026/04/20260424-163745--2026-04-25-003703--21e892504b82.png)
### 第十部分:订阅节点与自建推荐
### 第十部分:订阅节点与自建推荐
如果你还没有订阅节点或想要寻找稳定、便宜的科学上网方式,可以参考以下三种方案获取。
@@ -661,6 +769,23 @@ function main(config, profileName) {
请先确认脚本已经完整粘贴并保存,然后回到 `代理` 页面重新查看。若仍未出现,请继续确认当前订阅可用、`代理模式``规则模式`,并且 `系统代理` 已开启。
### 扩展 `IP代理` 开启后,为什么状态还是没有出口 IP?
先确认 Host、Port、协议、代理账号和代理密码都已填写正确。
修改这些字段后,需要点击 `同步` 才会重新应用代理并检测出口。
如果诊断提示没有收到 `407` 代理鉴权挑战,可以尝试点击 `Change`、关闭再开启 `IP代理`、更换 session,或者换一条代理节点。
### `Change` 按钮为什么点不了?
`Change` 只在 `711Proxy` 的账号密码模式下可用,并且当前生效用户名必须包含 `session-xxxx` 这类 session 参数。
如果没有 session,请先在 `会话(session)` 中填写一个随机前缀,再点击 `同步`
### `IP代理` 和 Clash Verge 应该同时开吗?
通常二选一即可。
如果开启扩展内置 `IP代理`,浏览器会优先使用扩展设置的 PAC 代理;如果关闭它,浏览器会回到默认网络或外部全局代理。
排查问题时建议先只保留一种代理方式,确认出口 IP 稳定后再继续流程。
### 网站测速结果好,是否代表节点纯净?
不代表。
@@ -688,6 +813,9 @@ function main(config, profileName) {
- 中国大陆居民注册 `PayPal` 个人账户时,姓名请按身份证上的中文姓名填写,不要使用拼音。
- `PayPal` 官方说明,绑定新卡时可能会向发卡行发送最高 `1 USD` 或等值货币的临时授权验证,所以完全没有余额的卡也可能因为授权失败而无法绑定。
- 为了控制风险,更稳妥的做法是使用单独管理、余额较低的借记卡,并在绑卡后及时检查 `钱包` 页面和右上角通知。
- 使用扩展内置 `IP代理` 时,修改 Host、Port、账号、密码、地区、session 或时长后,请点击 `同步` 让新配置真正生效。
- `711Proxy``Change` 需要用户名中包含 session;没有 session 时请先填写 `会话(session)` 并同步。
- 扩展 `IP代理` 报连通性失败时,不要直接继续自动流程,先用 `检测出口``检查IP` 确认网页看到的出口 IP。
- 检查节点时,先确认出口 IP,再看风险标签和泄露检测,最后再看网站测速。
- [TCPTest 网站测速](https://www.tcptest.cn/?cckey=e62f31db) 主要用于判断访问速度和连通性,不要单独用它判断节点纯净度。
- [IPPure](https://ippure.com/) 如果提示 `WebRTC``DNS` 泄露,请优先检查浏览器和代理客户端的相关设置。
+1 -1
View File
@@ -219,7 +219,7 @@
<option value="711proxy">711Proxy(首版)</option>
</select>
<button id="btn-ip-proxy-service-login" class="btn btn-outline btn-sm data-inline-btn" type="button">
登录
注册
</button>
</div>
</div>
+4 -3
View File
@@ -748,7 +748,7 @@ const IP_PROXY_SERVICE_LOGIN_CONFIGS = {
'711proxy': {
label: '711Proxy',
url: 'https://www.711proxy.com/signup?code=AD2497',
buttonLabel: '登录',
buttonLabel: '注册',
},
};
@@ -3844,9 +3844,10 @@ function updateIpProxyServiceLoginButtonState(options = {}) {
? Boolean(options.enabled)
: Boolean(getSelectedIpProxyEnabled());
btnIpProxyServiceLogin.disabled = !enabled || !loginUrl;
btnIpProxyServiceLogin.textContent = loginConfig?.buttonLabel || '登录';
const buttonLabel = loginConfig?.buttonLabel || '登录';
btnIpProxyServiceLogin.textContent = buttonLabel;
btnIpProxyServiceLogin.title = loginUrl
? `打开 ${loginConfig?.label || service} 登录`
? `打开 ${loginConfig?.label || service} ${buttonLabel}`
: '当前代理服务没有可跳转的登录页';
}
+105
View File
@@ -145,6 +145,57 @@ return {
`)(document, window);
}
function createSubmitApi(overrides = {}) {
const bindings = {
waitForDocumentComplete: async () => {},
normalizeText: (text = '') => String(text || '').replace(/\s+/g, ' ').trim(),
findPasswordInput: () => null,
findEmailInput: () => null,
findEmailNextButton: () => null,
isEnabledControl: () => true,
findPasswordLoginButton: () => null,
fillInput: () => {},
simulateClick: () => {},
waitUntil: async (predicate) => predicate(),
findLoginNextButton: () => null,
sleep: async () => {},
...overrides,
};
return new Function(
'waitForDocumentComplete',
'normalizeText',
'findPasswordInput',
'findEmailInput',
'findEmailNextButton',
'isEnabledControl',
'findPasswordLoginButton',
'fillInput',
'simulateClick',
'waitUntil',
'findLoginNextButton',
'sleep',
`
${extractFunction('refillPayPalEmailInput')}
${extractFunction('submitPayPalLogin')}
return { refillPayPalEmailInput, submitPayPalLogin };
`
)(
bindings.waitForDocumentComplete,
bindings.normalizeText,
bindings.findPasswordInput,
bindings.findEmailInput,
bindings.findEmailNextButton,
bindings.isEnabledControl,
bindings.findPasswordLoginButton,
bindings.fillInput,
bindings.simulateClick,
bindings.waitUntil,
bindings.findLoginNextButton,
bindings.sleep
);
}
test('PayPal email page ignores hidden pre-rendered password input', () => {
const hiddenPanel = createElement({ attrs: { 'aria-hidden': 'true' } });
const emailInput = createElement({
@@ -203,3 +254,57 @@ test('PayPal combined login page still sees visible password input', () => {
assert.equal(api.findPasswordLoginButton(), loginButton);
assert.equal(api.getPayPalLoginPhase(emailInput, passwordInput), 'login_combined');
});
test('PayPal email submit refills a prefilled email before clicking next', async () => {
const emailInput = createElement({
tag: 'input',
type: 'text',
id: 'login_email',
name: 'login_email',
value: 'user@example.com',
placeholder: 'Email',
});
const nextButton = createElement({
tag: 'button',
id: 'btnNext',
text: 'Next',
});
const fillValues = [];
const clicked = [];
let focusCount = 0;
let blurCount = 0;
emailInput.focus = () => {
focusCount += 1;
};
emailInput.blur = () => {
blurCount += 1;
};
const api = createSubmitApi({
findEmailInput: () => emailInput,
findEmailNextButton: () => nextButton,
fillInput: (element, value) => {
fillValues.push(value);
element.value = value;
},
simulateClick: (element) => {
clicked.push(element);
},
});
const result = await api.submitPayPalLogin({
email: 'user@example.com',
password: 'secret',
});
assert.deepEqual(fillValues, ['', 'user@example.com']);
assert.equal(focusCount, 1);
assert.equal(blurCount, 1);
assert.deepEqual(clicked, [nextButton]);
assert.deepEqual(result, {
submitted: false,
phase: 'email_submitted',
awaiting: 'password_page',
});
});
+1 -1
View File
@@ -500,7 +500,7 @@ Plus 模式可见步骤:
1. 第 1~5 步:沿用普通注册入口、邮箱、密码、注册验证码、资料填写链路。
2. 第 6 步 `创建 Plus Checkout`:打开已登录 ChatGPT 页面,通过 `/api/auth/session` 读取 accessToken,再请求 `https://chatgpt.com/backend-api/payments/checkout` 创建 `chatgptplusplan` 的 checkout session,并打开 `https://chatgpt.com/checkout/openai_ie/{checkout_session_id}`
3. 第 7 步 `填写账单并提交订阅`:选择 PayPal,生成账单全名,从 `data/address-sources.js` 读取同国家 seed query,触发 checkout 内置 Google 地址推荐,选择推荐项并校验地址第 1 行、城市、州/省、邮编等结构化字段,再点击“订阅”。运行时会按 Stripe iframe 拆分执行:付款方式在 `elements-inner-payment` frame,账单地址在 `elements-inner-address` frameGoogle 推荐在 `elements-inner-autocompl` frame 时单独点击推荐项。
4. 第 8 步 `PayPal 登录与授权`:在 PayPal 页面填写 `paypalEmail / paypalPassword`登录前固定等待 1 秒,关闭可见通行密钥提示,点击“同意并继续”。
4. 第 8 步 `PayPal 登录与授权`:在 PayPal 页面填写 `paypalEmail / paypalPassword`。当页面处于账号输入阶段时,内容脚本会固定对邮箱输入框执行 `focus -> clear -> fill -> blur -> click next`,即使文本框里已经预填了同一个账号,也会重新触发输入事件,避免 PayPal 因跳过重填而停在邮箱页;登录前固定等待 1 秒,关闭可见通行密钥提示,点击“同意并继续”。
5. 第 9 步 `订阅回跳确认`:等待 PayPal 授权后回跳到 ChatGPT / OpenAI 页面,页面加载完成后固定等待 1 秒。
6. 第 10 步:复用原 Step 7 OAuth 登录执行器,但状态和日志按 Plus 可见第 10 步记录。
7. 第 11 步:复用原 Step 8 登录验证码执行器,但状态和日志按 Plus 可见第 11 步记录。
+3 -1
View File
@@ -86,7 +86,7 @@
- `content/inbucket-mail.js`:Inbucket 邮箱轮询脚本,负责在 Inbucket 页面中读取、删除验证码邮件。
- `content/mail-163.js`163 / 163 VIP / 126 邮箱轮询脚本,负责网页邮箱验证码读取和邮件清理。
- `content/mail-2925.js`:2925 邮箱页面脚本,负责 2925 邮箱自动登录态确认、收件轮询、按步骤会话隔离“已试验证码”、在每次重发验证码之间执行一轮最多 15 次的邮箱刷新轮询、命中邮件后立即删当前邮件,以及在成功后配合后台执行整箱清理;若页面出现“子邮箱已达上限邮箱”提示,会立即上报后台进入切号链路;当后台显式开启 `mail2925MatchTargetEmail` 时,会对邮件里显式出现的目标邮箱做弱匹配,避免 `receive` 模式误捞别人的验证码。
- `content/paypal-flow.js`:PayPal 页面脚本,负责识别登录表单、填写 PayPal 账号密码、处理页面内可见通行密钥提示,并点击 PayPal 授权页的“同意并继续”按钮。
- `content/paypal-flow.js`:PayPal 页面脚本,负责识别登录表单、填写 PayPal 账号密码、在账号页固定执行 `focus -> clear -> fill -> blur` 重新触发邮箱输入事件、处理页面内可见通行密钥提示,并点击 PayPal 授权页的“同意并继续”按钮。
- `content/phone-auth.js`:认证页手机号验证脚本,负责识别 `add-phone / phone-verification` 页面、选择国家、填写手机号、提交短信验证码、触发重发短信,以及把“回到 add-phone / 进入 OAuth 同意页”的结果反馈给后台。
- `content/plus-checkout.js`ChatGPT Plus checkout 页面脚本,负责读取 `/api/auth/session` 创建 Plus checkout、选择 PayPal、填写账单姓名、触发 Google 地址推荐、校验结构化地址字段并点击订阅。
- `content/qq-mail.js`:QQ 邮箱轮询脚本,负责网页邮箱验证码读取。
@@ -202,6 +202,8 @@
- `tests/background-verification-flow-module.test.js`:测试验证码流程模块已接入且导出工厂。
- `tests/phone-auth-country-match.test.js`:测试认证页手机号国家选择在页面本地化时,仍能用 HeroSMS 的英文国家名匹配对应国家选项。
- `tests/phone-verification-flow.test.js`:测试手机号验证共享流程对 HeroSMS 的取号、复用、重发、换号与 Step 7 重开错误分支。
- `tests/paypal-approve-detection.test.js`:测试 Plus 第 8 步后台执行器对 PayPal 标签页发现、分离式账号/密码页识别、联合登录页识别,以及登录后直接离开 PayPal 页的分支判断。
- `tests/paypal-flow-content.test.js`:测试 PayPal 内容脚本对可见邮箱/密码输入框的识别,并覆盖邮箱页即使已预填相同账号也会先清空再重填后继续下一步。
- `tests/plus-checkout-billing-tab-resolution.test.js`:测试 Plus 第 7 步可直接接管当前 checkout 标签页,并把 PayPal、账单地址、Google 地址推荐和订阅按钮操作路由到对应 Stripe iframe。
- `tests/cloudflare-temp-email-provider.test.js`:测试 Cloudflare Temp Email provider 的轮询与目标邮箱选择逻辑。
- `tests/cloudflare-temp-email-utils.test.js`:测试 Cloudflare Temp Email 工具层的 URL、域名、邮件解析逻辑。