fix: 修复 2925 收件模式轮询与重复注入

- receive 模式下跳过 2925 邮箱页顶部账号校验
- 解析 bounce 转发地址与中文日期,避免误过滤验证码邮件
- 为内容脚本增加重复注入保护,避免重复声明导致轮询失效
This commit is contained in:
Isulew
2026-04-27 13:57:51 +08:00
parent c98cfd7053
commit b71bccaf8a
6 changed files with 74 additions and 7 deletions
+4
View File
@@ -69,6 +69,10 @@
}
function getExpectedMail2925MailboxEmail(state = {}) {
if (String(state?.mail2925Mode || '').trim().toLowerCase() === 'receive') {
return '';
}
if (Boolean(state?.mail2925UseAccountPool)) {
const currentAccountId = String(state?.currentMail2925AccountId || '').trim();
const accounts = Array.isArray(state?.mail2925Accounts) ? state.mail2925Accounts : [];
+4
View File
@@ -26,6 +26,10 @@
} = deps;
function getExpectedMail2925MailboxEmail(state = {}) {
if (String(state?.mail2925Mode || '').trim().toLowerCase() === 'receive') {
return '';
}
if (Boolean(state?.mail2925UseAccountPool)) {
const currentAccountId = String(state?.currentMail2925AccountId || '').trim();
const accounts = Array.isArray(state?.mail2925Accounts) ? state.mail2925Accounts : [];
+58 -2
View File
@@ -1,6 +1,13 @@
// content/mail-2925.js - Content script for 2925 Mail (steps 4, 8)
// Injected dynamically on: 2925.com
(function initMail2925ContentScript() {
if (window.__MULTIPAGE_MAIL2925_SCRIPT_LOADED__) {
console.log('[MultiPage:mail-2925] Duplicate injection skipped on', location.href);
return;
}
window.__MULTIPAGE_MAIL2925_SCRIPT_LOADED__ = true;
const MAIL2925_PREFIX = '[MultiPage:mail-2925]';
const isTopFrame = window === window.top;
@@ -699,10 +706,29 @@ function extractEmails(text = '') {
return [...new Set(matches.map((item) => item.toLowerCase()))];
}
function extractForwardedTargetEmails(text = '') {
const normalizedText = String(text || '').toLowerCase();
const matches = normalizedText.match(/bounce\+[a-z0-9._%+-]*-([a-z0-9._%+-]+)=([a-z0-9.-]+\.[a-z]{2,})@(?:tm\d*\.openai\.com|em\d+\.tm\.openai\.com)/gi) || [];
const decoded = matches
.map((candidate) => {
const match = String(candidate || '').match(/bounce\+[a-z0-9._%+-]*-([a-z0-9._%+-]+)=([a-z0-9.-]+\.[a-z]{2,})@/i);
if (!match) {
return '';
}
return `${match[1].toLowerCase()}@${match[2].toLowerCase()}`;
})
.filter(Boolean);
return [...new Set(decoded)];
}
function emailMatchesTarget(candidate, targetEmail) {
const normalizedCandidate = String(candidate || '').trim().toLowerCase();
const normalizedTarget = String(targetEmail || '').trim().toLowerCase();
return Boolean(normalizedCandidate && normalizedTarget && normalizedCandidate === normalizedTarget);
if (!normalizedCandidate || !normalizedTarget) {
return false;
}
return normalizedCandidate === normalizedTarget;
}
function getTargetEmailMatchState(text, targetEmail) {
@@ -717,12 +743,30 @@ function getTargetEmailMatchState(text, targetEmail) {
}
const extractedEmails = extractEmails(normalizedText);
const forwardedTargetEmails = extractForwardedTargetEmails(normalizedText);
if (!extractedEmails.length) {
return forwardedTargetEmails.length
? {
matches: forwardedTargetEmails.some((candidate) => emailMatchesTarget(candidate, normalizedTarget)),
hasExplicitEmail: true,
}
: { matches: true, hasExplicitEmail: false };
}
const targetDomain = normalizedTarget.includes('@')
? normalizedTarget.split('@').pop()
: '';
const comparableEmails = [...new Set(
(targetDomain
? [...extractedEmails, ...forwardedTargetEmails].filter((candidate) => String(candidate || '').trim().toLowerCase().endsWith(`@${targetDomain}`))
: [...extractedEmails, ...forwardedTargetEmails])
)];
if (!comparableEmails.length) {
return { matches: true, hasExplicitEmail: false };
}
return {
matches: extractedEmails.some((candidate) => emailMatchesTarget(candidate, normalizedTarget)),
matches: comparableEmails.some((candidate) => emailMatchesTarget(candidate, normalizedTarget)),
hasExplicitEmail: true,
};
}
@@ -782,6 +826,17 @@ function parseMailItemTimestamp(item) {
return date.getTime();
}
match = timeText.match(/(\d{1,2})月(\d{1,2})日(?:\s*(\d{1,2}):(\d{2}))?/);
if (match) {
date.setMonth(Number(match[1]) - 1, Number(match[2]));
if (match[3] && match[4]) {
date.setHours(Number(match[3]), Number(match[4]), 0, 0);
} else {
date.setHours(0, 0, 0, 0);
}
return date.getTime();
}
match = timeText.match(/(\d{4})-(\d{1,2})-(\d{1,2})\s*(\d{1,2}):(\d{2})/);
if (match) {
return new Date(
@@ -1168,3 +1223,4 @@ async function handlePollEmail(step, payload) {
}
}
})();
+2
View File
@@ -2,6 +2,7 @@
// Injected on: auth0.openai.com, auth.openai.com, accounts.openai.com
// Dynamically injected on: chatgpt.com
(function initSignupPageContentScript() {
console.log('[MultiPage:signup-page] Content script loaded on', location.href);
const SIGNUP_PAGE_LISTENER_SENTINEL = 'data-multipage-signup-page-listener';
@@ -3560,3 +3561,4 @@ async function step5_fillNameBirthday(payload) {
log('步骤 5:已点击“完成帐户创建”,当前步骤直接完成,不再等待页面结果。');
return completionPayload;
}
})();
+5 -5
View File
@@ -1,6 +1,6 @@
// content/utils.js — Shared utilities for all content scripts
const getActivationStrategy = self.MultiPageActivationUtils?.getActivationStrategy;
var getActivationStrategy = self.MultiPageActivationUtils?.getActivationStrategy;
function detectScriptSource({
injectedSource,
@@ -26,7 +26,7 @@ function detectScriptSource({
return 'vps-panel';
}
const SCRIPT_SOURCE = (() => {
var SCRIPT_SOURCE = (() => {
return detectScriptSource({
injectedSource: window.__MULTIPAGE_SOURCE,
url: location.href,
@@ -38,9 +38,9 @@ function getRuntimeScriptSource() {
return window.__MULTIPAGE_SOURCE || SCRIPT_SOURCE;
}
const LOG_PREFIX = `[MultiPage:${SCRIPT_SOURCE}]`;
const STOP_ERROR_MESSAGE = '流程已被用户停止。';
let flowStopped = false;
var LOG_PREFIX = `[MultiPage:${SCRIPT_SOURCE}]`;
var STOP_ERROR_MESSAGE = '流程已被用户停止。';
var flowStopped = false;
if (!window.__MULTIPAGE_UTILS_LISTENER_READY__) {
window.__MULTIPAGE_UTILS_LISTENER_READY__ = true;
+1
View File
@@ -319,6 +319,7 @@ return {
test('handlePollEmail skips explicit mismatched target emails when receive-mode matching is enabled', async () => {
const bundle = [
extractFunction('extractEmails'),
extractFunction('extractForwardedTargetEmails'),
extractFunction('emailMatchesTarget'),
extractFunction('getTargetEmailMatchState'),
extractFunction('normalizeMinuteTimestamp'),