增加对CloudMail(SkyMail)邮箱的支持
This commit is contained in:
+339
@@ -48,6 +48,7 @@ importScripts(
|
||||
'microsoft-email.js',
|
||||
'luckmail-utils.js',
|
||||
'cloudflare-temp-email-utils.js',
|
||||
'cloudmail-utils.js',
|
||||
'icloud-utils.js',
|
||||
'mail-provider-utils.js',
|
||||
'content/activation-utils.js'
|
||||
@@ -168,6 +169,17 @@ const {
|
||||
normalizeCloudflareTempEmailDomains,
|
||||
normalizeCloudflareTempEmailMailApiMessages,
|
||||
} = self.CloudflareTempEmailUtils;
|
||||
const {
|
||||
DEFAULT_MAIL_PAGE_SIZE: CLOUD_MAIL_DEFAULT_PAGE_SIZE,
|
||||
buildCloudMailHeaders,
|
||||
getCloudMailTokenFromResponse,
|
||||
joinCloudMailUrl,
|
||||
normalizeCloudMailAddress,
|
||||
normalizeCloudMailBaseUrl,
|
||||
normalizeCloudMailDomain,
|
||||
normalizeCloudMailDomains,
|
||||
normalizeCloudMailMailApiMessages,
|
||||
} = self.CloudMailUtils;
|
||||
const {
|
||||
findIcloudAliasByEmail,
|
||||
getConfiguredIcloudHostPreference,
|
||||
@@ -224,6 +236,8 @@ const HOTMAIL_PROVIDER = 'hotmail-api';
|
||||
const LUCKMAIL_PROVIDER = 'luckmail-api';
|
||||
const CLOUDFLARE_TEMP_EMAIL_PROVIDER = 'cloudflare-temp-email';
|
||||
const CLOUDFLARE_TEMP_EMAIL_GENERATOR = 'cloudflare-temp-email';
|
||||
const CLOUD_MAIL_PROVIDER = 'cloudmail';
|
||||
const CLOUD_MAIL_GENERATOR = 'cloudmail';
|
||||
const CUSTOM_EMAIL_POOL_GENERATOR = 'custom-pool';
|
||||
const HOTMAIL_MAILBOXES = ['INBOX', 'Junk'];
|
||||
const STOP_ERROR_MESSAGE = '流程已被用户停止。';
|
||||
@@ -684,6 +698,13 @@ const PERSISTED_SETTING_DEFAULTS = {
|
||||
cloudflareTempEmailUseRandomSubdomain: false,
|
||||
cloudflareTempEmailDomain: '',
|
||||
cloudflareTempEmailDomains: [],
|
||||
cloudMailBaseUrl: '',
|
||||
cloudMailAdminEmail: '',
|
||||
cloudMailAdminPassword: '',
|
||||
cloudMailToken: '',
|
||||
cloudMailReceiveMailbox: '',
|
||||
cloudMailDomain: '',
|
||||
cloudMailDomains: [],
|
||||
hotmailAccounts: [],
|
||||
mail2925Accounts: [],
|
||||
paypalAccounts: [],
|
||||
@@ -1664,6 +1685,7 @@ function normalizeEmailGenerator(value = '') {
|
||||
}
|
||||
if (normalized === 'cloudflare') return 'cloudflare';
|
||||
if (normalized === CLOUDFLARE_TEMP_EMAIL_GENERATOR) return CLOUDFLARE_TEMP_EMAIL_GENERATOR;
|
||||
if (normalized === 'cloudmail') return 'cloudmail';
|
||||
return 'duck';
|
||||
}
|
||||
|
||||
@@ -1897,6 +1919,7 @@ function normalizeMailProvider(value = '') {
|
||||
case HOTMAIL_PROVIDER:
|
||||
case LUCKMAIL_PROVIDER:
|
||||
case CLOUDFLARE_TEMP_EMAIL_PROVIDER:
|
||||
case CLOUD_MAIL_PROVIDER:
|
||||
case '163':
|
||||
case '163-vip':
|
||||
case '126':
|
||||
@@ -2092,6 +2115,42 @@ function resolveCloudflareTempEmailPollTargetEmail(state = {}, pollPayload = {},
|
||||
return normalizeCloudflareTempEmailReceiveMailbox(state.email);
|
||||
}
|
||||
|
||||
function getCloudMailConfig(state = {}) {
|
||||
return {
|
||||
baseUrl: normalizeCloudMailBaseUrl(state.cloudMailBaseUrl),
|
||||
adminEmail: String(state.cloudMailAdminEmail || '').trim(),
|
||||
adminPassword: String(state.cloudMailAdminPassword || ''),
|
||||
token: String(state.cloudMailToken || '').trim(),
|
||||
receiveMailbox: normalizeCloudMailReceiveMailbox(state.cloudMailReceiveMailbox),
|
||||
domain: normalizeCloudMailDomain(state.cloudMailDomain),
|
||||
domains: normalizeCloudMailDomains(state.cloudMailDomains),
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeCloudMailReceiveMailbox(value = '') {
|
||||
const normalized = normalizeCloudMailAddress(value);
|
||||
if (!normalized) return '';
|
||||
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(normalized) ? normalized : '';
|
||||
}
|
||||
|
||||
function resolveCloudMailPollTargetEmail(state = {}, pollPayload = {}, config = getCloudMailConfig(state)) {
|
||||
const configuredReceiveMailbox = normalizeCloudMailReceiveMailbox(config.receiveMailbox);
|
||||
const mailProvider = String(state?.mailProvider || '').trim().toLowerCase();
|
||||
const emailGenerator = String(state?.emailGenerator || '').trim().toLowerCase();
|
||||
const shouldPreferConfiguredReceiveMailbox = mailProvider === CLOUD_MAIL_PROVIDER
|
||||
&& emailGenerator !== CLOUD_MAIL_GENERATOR;
|
||||
if (shouldPreferConfiguredReceiveMailbox && configuredReceiveMailbox) {
|
||||
return configuredReceiveMailbox;
|
||||
}
|
||||
|
||||
const requestedTarget = normalizeCloudMailReceiveMailbox(pollPayload.targetEmail);
|
||||
if (requestedTarget) {
|
||||
return requestedTarget;
|
||||
}
|
||||
|
||||
return normalizeCloudMailReceiveMailbox(state.email);
|
||||
}
|
||||
|
||||
function normalizeSub2ApiGroupNames(value = '') {
|
||||
const source = Array.isArray(value)
|
||||
? value
|
||||
@@ -2402,6 +2461,19 @@ function normalizePersistentSettingValue(key, value) {
|
||||
return normalizeCloudflareTempEmailDomain(value);
|
||||
case 'cloudflareTempEmailDomains':
|
||||
return normalizeCloudflareTempEmailDomains(value);
|
||||
case 'cloudMailBaseUrl':
|
||||
return normalizeCloudMailBaseUrl(value);
|
||||
case 'cloudMailAdminEmail':
|
||||
return String(value || '').trim();
|
||||
case 'cloudMailAdminPassword':
|
||||
case 'cloudMailToken':
|
||||
return String(value || '');
|
||||
case 'cloudMailReceiveMailbox':
|
||||
return normalizeCloudMailReceiveMailbox(value);
|
||||
case 'cloudMailDomain':
|
||||
return normalizeCloudMailDomain(value);
|
||||
case 'cloudMailDomains':
|
||||
return normalizeCloudMailDomains(value);
|
||||
case 'hotmailAccounts':
|
||||
return normalizeHotmailAccounts(value);
|
||||
case 'mail2925Accounts':
|
||||
@@ -2511,6 +2583,13 @@ function buildPersistentSettingsPayload(input = {}, options = {}) {
|
||||
}
|
||||
payload.cloudflareTempEmailDomains = domains;
|
||||
}
|
||||
if (payload.cloudMailDomains) {
|
||||
const domains = normalizeCloudMailDomains(payload.cloudMailDomains);
|
||||
if (payload.cloudMailDomain && !domains.includes(payload.cloudMailDomain)) {
|
||||
domains.unshift(payload.cloudMailDomain);
|
||||
}
|
||||
payload.cloudMailDomains = domains;
|
||||
}
|
||||
if (
|
||||
Object.prototype.hasOwnProperty.call(payload, 'sub2apiGroupName')
|
||||
|| Object.prototype.hasOwnProperty.call(payload, 'sub2apiGroupNames')
|
||||
@@ -5255,6 +5334,252 @@ async function pollCloudflareTempEmailVerificationCode(step, state, pollPayload
|
||||
throw lastError || new Error(`步骤 ${step}:未在 Cloudflare Temp Email 中找到新的匹配验证码。`);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Cloud Mail (skymail.ink) Integration
|
||||
// ============================================================
|
||||
|
||||
function ensureCloudMailConfig(state, options = {}) {
|
||||
const { requireToken = false, requireCredentials = false, requireDomain = false } = options;
|
||||
const config = getCloudMailConfig(state);
|
||||
if (!config.baseUrl) {
|
||||
throw new Error('Cloud Mail 服务地址为空或格式无效。');
|
||||
}
|
||||
if (requireCredentials && (!config.adminEmail || !config.adminPassword)) {
|
||||
throw new Error('Cloud Mail 缺少管理员邮箱或密码。');
|
||||
}
|
||||
if (requireToken && !config.token) {
|
||||
throw new Error('Cloud Mail 尚未获取到身份令牌,请先生成 Token。');
|
||||
}
|
||||
if (requireDomain && !config.domain) {
|
||||
throw new Error('Cloud Mail 域名为空或格式无效。');
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
async function requestCloudMailJson(config, path, options = {}) {
|
||||
const {
|
||||
method = 'POST',
|
||||
payload,
|
||||
timeoutMs = 20000,
|
||||
requireToken = true,
|
||||
} = options;
|
||||
const url = joinCloudMailUrl(config.baseUrl, path);
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => controller.abort(new Error('timeout')), timeoutMs);
|
||||
let response;
|
||||
try {
|
||||
response = await fetch(url, {
|
||||
method,
|
||||
headers: buildCloudMailHeaders(config, {
|
||||
json: payload !== undefined,
|
||||
token: requireToken ? undefined : '',
|
||||
}),
|
||||
body: payload !== undefined ? JSON.stringify(payload) : undefined,
|
||||
signal: controller.signal,
|
||||
});
|
||||
} catch (err) {
|
||||
const errorMessage = err?.name === 'AbortError'
|
||||
? `Cloud Mail 请求超时(>${Math.round(timeoutMs / 1000)} 秒)`
|
||||
: `Cloud Mail 请求失败:${err.message}`;
|
||||
throw new Error(errorMessage);
|
||||
} finally {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
const text = await response.text();
|
||||
let parsed;
|
||||
try {
|
||||
parsed = text ? JSON.parse(text) : {};
|
||||
} catch {
|
||||
parsed = text;
|
||||
}
|
||||
if (!response.ok) {
|
||||
const payloadError = typeof parsed === 'object' && parsed
|
||||
? (parsed.message || parsed.error || parsed.msg)
|
||||
: '';
|
||||
throw new Error(`Cloud Mail 请求失败:${payloadError || text || `HTTP ${response.status}`}`);
|
||||
}
|
||||
if (parsed && typeof parsed === 'object' && 'code' in parsed && Number(parsed.code) !== 200) {
|
||||
throw new Error(`Cloud Mail 业务错误:${parsed.message || parsed.msg || `code=${parsed.code}`}`);
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
async function ensureCloudMailToken(state, options = {}) {
|
||||
const { forceRefresh = false } = options;
|
||||
const latestState = state || await getState();
|
||||
const config = ensureCloudMailConfig(latestState, { requireCredentials: true });
|
||||
if (!forceRefresh && config.token) {
|
||||
return { config, token: config.token };
|
||||
}
|
||||
const loginConfig = { ...config, token: '' };
|
||||
const result = await requestCloudMailJson(loginConfig, '/api/public/genToken', {
|
||||
method: 'POST',
|
||||
payload: { email: config.adminEmail, password: config.adminPassword },
|
||||
requireToken: false,
|
||||
});
|
||||
const token = getCloudMailTokenFromResponse(result);
|
||||
if (!token) {
|
||||
throw new Error('Cloud Mail 未返回可用 Token。');
|
||||
}
|
||||
await setPersistentSettings({ cloudMailToken: token });
|
||||
return { config: { ...config, token }, token };
|
||||
}
|
||||
|
||||
function generateCloudMailAliasLocalPart() {
|
||||
const letters = 'abcdefghijklmnopqrstuvwxyz';
|
||||
const digits = '0123456789';
|
||||
const chars = [];
|
||||
for (let i = 0; i < 6; i++) chars.push(letters[Math.floor(Math.random() * letters.length)]);
|
||||
for (let i = 0; i < 4; i++) chars.push(digits[Math.floor(Math.random() * digits.length)]);
|
||||
for (let i = chars.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[chars[i], chars[j]] = [chars[j], chars[i]];
|
||||
}
|
||||
return chars.join('');
|
||||
}
|
||||
|
||||
async function fetchCloudMailAddress(state, options = {}) {
|
||||
throwIfStopped();
|
||||
const latestState = state || await getState();
|
||||
const { config } = await ensureCloudMailToken(latestState);
|
||||
const ensuredConfig = ensureCloudMailConfig({ ...latestState, cloudMailToken: config.token }, {
|
||||
requireToken: true,
|
||||
requireDomain: true,
|
||||
});
|
||||
const requestedLocal = String(options.localPart || options.name || '').trim().toLowerCase()
|
||||
|| generateCloudMailAliasLocalPart();
|
||||
const address = `${requestedLocal}@${ensuredConfig.domain}`.toLowerCase();
|
||||
const payload = { list: [{ email: address }] };
|
||||
try {
|
||||
await requestCloudMailJson(ensuredConfig, '/api/public/addUser', { method: 'POST', payload });
|
||||
} catch (err) {
|
||||
if (/token|unauthor|401/i.test(String(err?.message || ''))) {
|
||||
const refreshed = await ensureCloudMailToken(latestState, { forceRefresh: true });
|
||||
await requestCloudMailJson(refreshed.config, '/api/public/addUser', { method: 'POST', payload });
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
await setEmailState(address);
|
||||
await addLog(`Cloud Mail:已生成 ${address}`, 'ok');
|
||||
return address;
|
||||
}
|
||||
|
||||
function summarizeCloudMailMessagesForLog(messages) {
|
||||
return (messages || [])
|
||||
.slice()
|
||||
.sort((left, right) => {
|
||||
const leftTime = Date.parse(left.receivedDateTime || '') || 0;
|
||||
const rightTime = Date.parse(right.receivedDateTime || '') || 0;
|
||||
return rightTime - leftTime;
|
||||
})
|
||||
.slice(0, 3)
|
||||
.map((message) => {
|
||||
const receivedAt = message?.receivedDateTime || '未知时间';
|
||||
const sender = message?.from?.emailAddress?.address || '未知发件人';
|
||||
const subject = message?.subject || '(无主题)';
|
||||
const preview = String(message?.bodyPreview || '').replace(/\s+/g, ' ').trim().slice(0, 80);
|
||||
const address = message?.address || '未知地址';
|
||||
return `[${address}] ${receivedAt} | ${sender} | ${subject} | ${preview}`;
|
||||
})
|
||||
.join(' || ');
|
||||
}
|
||||
|
||||
async function listCloudMailMessages(state, options = {}) {
|
||||
const latestState = state || await getState();
|
||||
const { config } = await ensureCloudMailToken(latestState);
|
||||
const address = normalizeCloudMailAddress(options.address);
|
||||
const pageSize = Number(options.limit) || CLOUD_MAIL_DEFAULT_PAGE_SIZE;
|
||||
const pageNum = Number(options.page) || 1;
|
||||
const request = async (currentConfig) => requestCloudMailJson(currentConfig, '/api/public/emailList', {
|
||||
method: 'POST',
|
||||
payload: {
|
||||
toEmail: address || undefined,
|
||||
type: 0,
|
||||
isDel: 0,
|
||||
timeSort: 'desc',
|
||||
num: pageNum,
|
||||
size: pageSize,
|
||||
},
|
||||
});
|
||||
let payload;
|
||||
try {
|
||||
payload = await request(config);
|
||||
} catch (err) {
|
||||
if (/token|unauthor|401/i.test(String(err?.message || ''))) {
|
||||
const refreshed = await ensureCloudMailToken(latestState, { forceRefresh: true });
|
||||
payload = await request(refreshed.config);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
const messages = normalizeCloudMailMailApiMessages(payload).filter((message) => {
|
||||
if (!address) return true;
|
||||
return !message.address || normalizeCloudMailAddress(message.address) === address;
|
||||
});
|
||||
return { config, messages };
|
||||
}
|
||||
|
||||
async function pollCloudMailVerificationCode(step, state, pollPayload = {}) {
|
||||
const latestState = state || await getState();
|
||||
const config = ensureCloudMailConfig(latestState, { requireCredentials: true });
|
||||
const targetEmail = resolveCloudMailPollTargetEmail(latestState, pollPayload, config);
|
||||
const registrationEmail = normalizeCloudMailReceiveMailbox(latestState.email);
|
||||
if (!targetEmail) {
|
||||
throw new Error('Cloud Mail 轮询前缺少目标邮箱地址,请先填写注册邮箱或"邮件接收"邮箱。');
|
||||
}
|
||||
if (registrationEmail && registrationEmail !== targetEmail) {
|
||||
await addLog(`步骤 ${step}:正在轮询 Cloud Mail 收件邮箱(${targetEmail}),注册邮箱为 ${registrationEmail}...`, 'info');
|
||||
} else {
|
||||
await addLog(`步骤 ${step}:正在轮询 Cloud Mail 邮件(${targetEmail})...`, 'info');
|
||||
}
|
||||
const maxAttempts = Number(pollPayload.maxAttempts) || 5;
|
||||
const intervalMs = Number(pollPayload.intervalMs) || 3000;
|
||||
let lastError = null;
|
||||
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
||||
throwIfStopped();
|
||||
try {
|
||||
const { messages } = await listCloudMailMessages(latestState, {
|
||||
address: targetEmail,
|
||||
limit: pollPayload.limit || CLOUD_MAIL_DEFAULT_PAGE_SIZE,
|
||||
page: pollPayload.page || 1,
|
||||
});
|
||||
const matchResult = pickVerificationMessageWithTimeFallback(messages, {
|
||||
afterTimestamp: pollPayload.filterAfterTimestamp || 0,
|
||||
senderFilters: pollPayload.senderFilters || [],
|
||||
subjectFilters: pollPayload.subjectFilters || [],
|
||||
excludeCodes: pollPayload.excludeCodes || [],
|
||||
});
|
||||
const match = matchResult.match;
|
||||
if (match?.code) {
|
||||
if (matchResult.usedRelaxedFilters) {
|
||||
const fallbackLabel = matchResult.usedTimeFallback ? '宽松匹配 + 时间回退' : '宽松匹配';
|
||||
await addLog(`步骤 ${step}:严格规则未命中,已改用 ${fallbackLabel} 并命中 Cloud Mail 验证码。`, 'warn');
|
||||
}
|
||||
return {
|
||||
ok: true,
|
||||
code: match.code,
|
||||
emailTimestamp: match.receivedAt || Date.now(),
|
||||
mailId: match.message?.id || '',
|
||||
};
|
||||
}
|
||||
lastError = new Error(`步骤 ${step}:暂未在 Cloud Mail 中找到匹配验证码(${attempt}/${maxAttempts})。`);
|
||||
await addLog(lastError.message, attempt === maxAttempts ? 'warn' : 'info');
|
||||
const sample = summarizeCloudMailMessagesForLog(messages);
|
||||
if (sample) {
|
||||
await addLog(`步骤 ${step}:最近邮件样本:${sample}`, 'info');
|
||||
}
|
||||
} catch (err) {
|
||||
lastError = err;
|
||||
await addLog(`步骤 ${step}:Cloud Mail 轮询失败:${err.message}`, 'warn');
|
||||
}
|
||||
if (attempt < maxAttempts) {
|
||||
await sleepWithStop(intervalMs);
|
||||
}
|
||||
}
|
||||
throw lastError || new Error(`步骤 ${step}:未在 Cloud Mail 中找到新的匹配验证码。`);
|
||||
}
|
||||
|
||||
async function getOpenIcloudHostPreference() {
|
||||
try {
|
||||
const tabs = await chrome.tabs.query({
|
||||
@@ -7178,6 +7503,7 @@ function getSourceLabel(source) {
|
||||
'hotmail-api': 'Hotmail(API对接/本地助手)',
|
||||
'luckmail-api': 'LuckMail(API 购邮)',
|
||||
'cloudflare-temp-email': 'Cloudflare Temp Email',
|
||||
'cloudmail': 'Cloud Mail',
|
||||
'plus-checkout': 'Plus Checkout',
|
||||
'paypal-flow': 'PayPal 授权页',
|
||||
};
|
||||
@@ -9167,6 +9493,7 @@ function getEmailGeneratorLabel(generator) {
|
||||
}
|
||||
if (generator === 'cloudflare') return 'Cloudflare 邮箱';
|
||||
if (generator === CLOUDFLARE_TEMP_EMAIL_GENERATOR) return 'Cloudflare Temp Email';
|
||||
if (generator === CLOUD_MAIL_GENERATOR) return 'Cloud Mail';
|
||||
return 'Duck 邮箱';
|
||||
}
|
||||
const mail2925SessionManager = self.MultiPageBackgroundMail2925Session?.createMail2925SessionManager({
|
||||
@@ -9340,6 +9667,11 @@ async function fetchDuckEmail(options = {}) {
|
||||
}
|
||||
|
||||
async function fetchGeneratedEmail(state, options = {}) {
|
||||
const currentState = state || await getState();
|
||||
const generator = normalizeEmailGenerator(options.generator ?? currentState.emailGenerator);
|
||||
if (generator === CLOUD_MAIL_GENERATOR) {
|
||||
return fetchCloudMailAddress(currentState, options);
|
||||
}
|
||||
return generatedEmailHelpers.fetchGeneratedEmail(state, options);
|
||||
}
|
||||
|
||||
@@ -10439,6 +10771,7 @@ const verificationFlowHelpers = self.MultiPageBackgroundVerificationFlow?.create
|
||||
chrome,
|
||||
closeConflictingTabsForSource,
|
||||
CLOUDFLARE_TEMP_EMAIL_PROVIDER,
|
||||
CLOUD_MAIL_PROVIDER,
|
||||
completeStepFromBackground,
|
||||
confirmCustomVerificationStepBypassRequest: (step) => chrome.runtime.sendMessage({
|
||||
type: 'REQUEST_CUSTOM_VERIFICATION_BYPASS_CONFIRMATION',
|
||||
@@ -10457,6 +10790,7 @@ const verificationFlowHelpers = self.MultiPageBackgroundVerificationFlow?.create
|
||||
MAIL_2925_VERIFICATION_INTERVAL_MS,
|
||||
MAIL_2925_VERIFICATION_MAX_ATTEMPTS,
|
||||
pollCloudflareTempEmailVerificationCode,
|
||||
pollCloudMailVerificationCode,
|
||||
pollHotmailVerificationCode,
|
||||
pollLuckmailVerificationCode,
|
||||
sendToContentScript,
|
||||
@@ -10562,6 +10896,7 @@ const step4Executor = self.MultiPageBackgroundStep4?.createStep4Executor({
|
||||
isTabAlive,
|
||||
LUCKMAIL_PROVIDER,
|
||||
CLOUDFLARE_TEMP_EMAIL_PROVIDER,
|
||||
CLOUD_MAIL_PROVIDER,
|
||||
resolveVerificationStep: verificationFlowHelpers.resolveVerificationStep,
|
||||
reuseOrCreateTab,
|
||||
sendToContentScript,
|
||||
@@ -10607,6 +10942,7 @@ const step8Executor = self.MultiPageBackgroundStep8?.createStep8Executor({
|
||||
addLog,
|
||||
chrome,
|
||||
CLOUDFLARE_TEMP_EMAIL_PROVIDER,
|
||||
CLOUD_MAIL_PROVIDER,
|
||||
completeStepFromBackground,
|
||||
confirmCustomVerificationStepBypass: verificationFlowHelpers.confirmCustomVerificationStepBypass,
|
||||
ensureMail2925MailboxSession,
|
||||
@@ -11024,6 +11360,9 @@ function getMailConfig(state) {
|
||||
if (provider === CLOUDFLARE_TEMP_EMAIL_PROVIDER) {
|
||||
return { provider: CLOUDFLARE_TEMP_EMAIL_PROVIDER, label: 'Cloudflare Temp Email' };
|
||||
}
|
||||
if (provider === 'cloudmail') {
|
||||
return { provider: 'cloudmail', label: 'Cloud Mail' };
|
||||
}
|
||||
if (provider === '163') {
|
||||
return { source: 'mail-163', url: 'https://mail.163.com/js6/main.jsp?df=mail163_letter#module=mbox.ListModule%7C%7B%22fid%22%3A1%2C%22order%22%3A%22date%22%2C%22desc%22%3Atrue%7D', label: '163 邮箱' };
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
'hotmail-api': 'Hotmail(API对接/本地助手)',
|
||||
'luckmail-api': 'LuckMail(API 购邮)',
|
||||
'cloudflare-temp-email': 'Cloudflare Temp Email',
|
||||
'cloudmail': 'Cloud Mail',
|
||||
};
|
||||
return labels[source] || source || '未知来源';
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
addLog: rawAddLog = async () => {},
|
||||
chrome,
|
||||
CLOUDFLARE_TEMP_EMAIL_PROVIDER,
|
||||
CLOUD_MAIL_PROVIDER = 'cloudmail',
|
||||
completeStepFromBackground,
|
||||
confirmCustomVerificationStepBypass,
|
||||
ensureMail2925MailboxSession,
|
||||
@@ -484,6 +485,7 @@
|
||||
mail.provider === HOTMAIL_PROVIDER
|
||||
|| mail.provider === LUCKMAIL_PROVIDER
|
||||
|| mail.provider === CLOUDFLARE_TEMP_EMAIL_PROVIDER
|
||||
|| mail.provider === CLOUD_MAIL_PROVIDER
|
||||
) {
|
||||
await addLog(`步骤 ${visibleStep}:正在通过 ${mail.label} 轮询验证码...`);
|
||||
} else {
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
isTabAlive,
|
||||
LUCKMAIL_PROVIDER,
|
||||
CLOUDFLARE_TEMP_EMAIL_PROVIDER,
|
||||
CLOUD_MAIL_PROVIDER = 'cloudmail',
|
||||
resolveVerificationStep,
|
||||
reuseOrCreateTab,
|
||||
sendToContentScript,
|
||||
@@ -238,6 +239,7 @@
|
||||
mail.provider === HOTMAIL_PROVIDER
|
||||
|| mail.provider === LUCKMAIL_PROVIDER
|
||||
|| mail.provider === CLOUDFLARE_TEMP_EMAIL_PROVIDER
|
||||
|| mail.provider === CLOUD_MAIL_PROVIDER
|
||||
) {
|
||||
await addLog(`步骤 4:正在通过 ${mail.label} 轮询验证码...`);
|
||||
} else if (mail.provider === '2925') {
|
||||
@@ -263,6 +265,7 @@
|
||||
HOTMAIL_PROVIDER,
|
||||
LUCKMAIL_PROVIDER,
|
||||
CLOUDFLARE_TEMP_EMAIL_PROVIDER,
|
||||
CLOUD_MAIL_PROVIDER,
|
||||
].includes(mail.provider);
|
||||
const signupProfile = buildSignupProfileForVerificationStep();
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
chrome,
|
||||
closeConflictingTabsForSource,
|
||||
CLOUDFLARE_TEMP_EMAIL_PROVIDER,
|
||||
CLOUD_MAIL_PROVIDER = 'cloudmail',
|
||||
completeStepFromBackground,
|
||||
confirmCustomVerificationStepBypassRequest,
|
||||
getHotmailVerificationPollConfig,
|
||||
@@ -24,6 +25,7 @@
|
||||
MAIL_2925_VERIFICATION_INTERVAL_MS,
|
||||
MAIL_2925_VERIFICATION_MAX_ATTEMPTS,
|
||||
pollCloudflareTempEmailVerificationCode,
|
||||
pollCloudMailVerificationCode,
|
||||
pollHotmailVerificationCode,
|
||||
pollLuckmailVerificationCode,
|
||||
sendToContentScript,
|
||||
@@ -927,6 +929,13 @@
|
||||
}, cleanPollOverrides, `轮询${getVerificationCodeLabel(step)}验证码邮箱`);
|
||||
return pollCloudflareTempEmailVerificationCode(step, state, timedPoll.payload);
|
||||
}
|
||||
if (mail.provider === CLOUD_MAIL_PROVIDER) {
|
||||
const timedPoll = await applyMailPollingTimeBudget(step, {
|
||||
...getVerificationPollPayload(step, state),
|
||||
...cleanPollOverrides,
|
||||
}, cleanPollOverrides, `轮询${getVerificationCodeLabel(step)}验证码邮箱`);
|
||||
return pollCloudMailVerificationCode(step, state, timedPoll.payload);
|
||||
}
|
||||
|
||||
if (Number(pollOverrides.resendIntervalMs) > 0) {
|
||||
return pollFreshVerificationCodeWithResendInterval(step, state, mail, pollOverrides);
|
||||
|
||||
@@ -406,6 +406,7 @@
|
||||
<option value="2925">2925 邮箱 (2925.com)</option>
|
||||
<option value="gmail">Gmail 邮箱 (mail.google.com)</option>
|
||||
<option value="cloudflare-temp-email">Cloudflare Temp Email</option>
|
||||
<option value="cloudmail">Cloud Mail</option>
|
||||
</select>
|
||||
<button id="btn-mail-login" class="btn btn-outline btn-sm data-inline-btn" type="button" disabled>登录</button>
|
||||
</div>
|
||||
@@ -431,6 +432,7 @@
|
||||
<option value="cloudflare">Cloudflare</option>
|
||||
<option value="icloud">iCloud 隐私邮箱</option>
|
||||
<option value="cloudflare-temp-email">Cloudflare Temp Email</option>
|
||||
<option value="cloudmail">Cloud Mail</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="data-row data-check-row" id="row-custom-email-pool" style="display:none;">
|
||||
@@ -684,6 +686,41 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="cloud-mail-section" class="data-card hotmail-card" style="display:none;">
|
||||
<div class="section-mini-header">
|
||||
<div class="section-mini-copy">
|
||||
<span class="section-label">Cloud Mail</span>
|
||||
<span class="data-value">用于生成邮箱或接收转发邮件(skymail.ink API)</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-row" id="row-cloud-mail-base-url" style="display:none;">
|
||||
<span class="data-label">API 地址</span>
|
||||
<input type="text" id="input-cloud-mail-base-url" class="data-input" placeholder="https://your-cloudmail-domain" />
|
||||
</div>
|
||||
<div class="data-row" id="row-cloud-mail-admin-email" style="display:none;">
|
||||
<span class="data-label">管理员邮箱</span>
|
||||
<input type="text" id="input-cloud-mail-admin-email" class="data-input" placeholder="admin@example.com" />
|
||||
</div>
|
||||
<div class="data-row" id="row-cloud-mail-admin-password" style="display:none;">
|
||||
<span class="data-label">管理员密码</span>
|
||||
<div class="input-with-icon">
|
||||
<input type="password" id="input-cloud-mail-admin-password" class="data-input data-input-with-icon"
|
||||
placeholder="Cloud Mail 管理员密码" />
|
||||
<button id="btn-toggle-cloud-mail-admin-password" class="input-icon-btn" type="button"
|
||||
data-password-toggle="input-cloud-mail-admin-password" data-show-label="显示 Cloud Mail 密码"
|
||||
data-hide-label="隐藏 Cloud Mail 密码" aria-label="显示 Cloud Mail 密码" title="显示 Cloud Mail 密码"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-row" id="row-cloud-mail-receive-mailbox" style="display:none;">
|
||||
<span class="data-label">邮件接收</span>
|
||||
<input type="text" id="input-cloud-mail-receive-mailbox" class="data-input"
|
||||
placeholder="用于接收转发邮件的邮箱,例如 1@email.example.com" />
|
||||
</div>
|
||||
<div class="data-row" id="row-cloud-mail-domain" style="display:none;">
|
||||
<span class="data-label">域名</span>
|
||||
<input type="text" id="input-cloud-mail-domain" class="data-input" placeholder="例如 mail.example.com" />
|
||||
</div>
|
||||
</div>
|
||||
<div id="hotmail-section" class="data-card hotmail-card" style="display:none;">
|
||||
<div class="section-mini-header">
|
||||
<div class="section-mini-copy">
|
||||
|
||||
+89
-1
@@ -261,6 +261,17 @@ const btnTempEmailDomainMode = document.getElementById('btn-temp-email-domain-mo
|
||||
const cloudflareTempEmailSection = document.getElementById('cloudflare-temp-email-section');
|
||||
const btnCloudflareTempEmailUsageGuide = document.getElementById('btn-cloudflare-temp-email-usage-guide');
|
||||
const btnCloudflareTempEmailGithub = document.getElementById('btn-cloudflare-temp-email-github');
|
||||
const cloudMailSection = document.getElementById('cloud-mail-section');
|
||||
const rowCloudMailBaseUrl = document.getElementById('row-cloud-mail-base-url');
|
||||
const rowCloudMailAdminEmail = document.getElementById('row-cloud-mail-admin-email');
|
||||
const rowCloudMailAdminPassword = document.getElementById('row-cloud-mail-admin-password');
|
||||
const rowCloudMailReceiveMailbox = document.getElementById('row-cloud-mail-receive-mailbox');
|
||||
const rowCloudMailDomain = document.getElementById('row-cloud-mail-domain');
|
||||
const inputCloudMailBaseUrl = document.getElementById('input-cloud-mail-base-url');
|
||||
const inputCloudMailAdminEmail = document.getElementById('input-cloud-mail-admin-email');
|
||||
const inputCloudMailAdminPassword = document.getElementById('input-cloud-mail-admin-password');
|
||||
const inputCloudMailReceiveMailbox = document.getElementById('input-cloud-mail-receive-mailbox');
|
||||
const inputCloudMailDomain = document.getElementById('input-cloud-mail-domain');
|
||||
const hotmailSection = document.getElementById('hotmail-section');
|
||||
const mail2925Section = document.getElementById('mail2925-section');
|
||||
const luckmailSection = document.getElementById('luckmail-section');
|
||||
@@ -2616,6 +2627,18 @@ function normalizeCloudflareTempEmailDomains(values = []) {
|
||||
return domains;
|
||||
}
|
||||
|
||||
function normalizeCloudMailBaseUrlValue(value = '') {
|
||||
return normalizeCloudflareTempEmailBaseUrlValue(value);
|
||||
}
|
||||
|
||||
function normalizeCloudMailReceiveMailboxValue(value = '') {
|
||||
return normalizeCloudflareTempEmailReceiveMailboxValue(value);
|
||||
}
|
||||
|
||||
function normalizeCloudMailDomainValue(value = '') {
|
||||
return normalizeCloudflareDomainValue(value);
|
||||
}
|
||||
|
||||
function getCloudflareDomainsFromState() {
|
||||
const domains = normalizeCloudflareDomains(latestState?.cloudflareDomains || []);
|
||||
const activeDomain = normalizeCloudflareDomainValue(latestState?.cloudflareDomain || '');
|
||||
@@ -2692,6 +2715,24 @@ function applyCloudflareTempEmailSettingsState(state = {}) {
|
||||
setCloudflareTempEmailDomainEditMode(false, { clearInput: true });
|
||||
}
|
||||
|
||||
function applyCloudMailSettingsState(state = {}) {
|
||||
if (inputCloudMailBaseUrl) {
|
||||
inputCloudMailBaseUrl.value = state?.cloudMailBaseUrl || '';
|
||||
}
|
||||
if (inputCloudMailAdminEmail) {
|
||||
inputCloudMailAdminEmail.value = state?.cloudMailAdminEmail || '';
|
||||
}
|
||||
if (inputCloudMailAdminPassword) {
|
||||
inputCloudMailAdminPassword.value = state?.cloudMailAdminPassword || '';
|
||||
}
|
||||
if (inputCloudMailReceiveMailbox) {
|
||||
inputCloudMailReceiveMailbox.value = state?.cloudMailReceiveMailbox || '';
|
||||
}
|
||||
if (inputCloudMailDomain) {
|
||||
inputCloudMailDomain.value = state?.cloudMailDomain || '';
|
||||
}
|
||||
}
|
||||
|
||||
function collectSettingsPayload() {
|
||||
const defaultGpcHelperApiUrl = typeof DEFAULT_GPC_HELPER_API_URL !== 'undefined'
|
||||
? DEFAULT_GPC_HELPER_API_URL
|
||||
@@ -3355,6 +3396,11 @@ function collectSettingsPayload() {
|
||||
cloudflareTempEmailUseRandomSubdomain: Boolean(inputTempEmailUseRandomSubdomain?.checked),
|
||||
cloudflareTempEmailDomain: selectedCloudflareTempEmailDomain,
|
||||
cloudflareTempEmailDomains: tempEmailDomains,
|
||||
cloudMailBaseUrl: normalizeCloudflareTempEmailBaseUrlValue((typeof inputCloudMailBaseUrl !== 'undefined' && inputCloudMailBaseUrl) ? inputCloudMailBaseUrl.value : ''),
|
||||
cloudMailAdminEmail: ((typeof inputCloudMailAdminEmail !== 'undefined' && inputCloudMailAdminEmail) ? inputCloudMailAdminEmail.value : '').trim(),
|
||||
cloudMailAdminPassword: (typeof inputCloudMailAdminPassword !== 'undefined' && inputCloudMailAdminPassword) ? inputCloudMailAdminPassword.value : '',
|
||||
cloudMailReceiveMailbox: normalizeCloudflareTempEmailReceiveMailboxValue((typeof inputCloudMailReceiveMailbox !== 'undefined' && inputCloudMailReceiveMailbox) ? inputCloudMailReceiveMailbox.value : ''),
|
||||
cloudMailDomain: normalizeCloudflareTempEmailDomainValue((typeof inputCloudMailDomain !== 'undefined' && inputCloudMailDomain) ? inputCloudMailDomain.value : ''),
|
||||
autoRunSkipFailures: inputAutoSkipFailures.checked,
|
||||
autoRunFallbackThreadIntervalMinutes: normalizeAutoRunThreadIntervalMinutes(inputAutoSkipFailuresThreadIntervalMinutes.value),
|
||||
autoRunDelayEnabled: inputAutoDelayEnabled.checked,
|
||||
@@ -8086,7 +8132,7 @@ function applySettingsState(state) {
|
||||
inputCodex2ApiUrl.value = state?.codex2apiUrl || '';
|
||||
inputCodex2ApiAdminKey.value = state?.codex2apiAdminKey || '';
|
||||
const restoredMailProvider = isCustomMailProvider(state?.mailProvider)
|
||||
|| [ICLOUD_PROVIDER, 'hotmail-api', GMAIL_PROVIDER, 'luckmail-api', '163', '163-vip', '126', 'qq', 'inbucket', '2925', 'cloudflare-temp-email'].includes(String(state?.mailProvider || '').trim())
|
||||
|| [ICLOUD_PROVIDER, 'hotmail-api', GMAIL_PROVIDER, 'luckmail-api', '163', '163-vip', '126', 'qq', 'inbucket', '2925', 'cloudflare-temp-email', 'cloudmail'].includes(String(state?.mailProvider || '').trim())
|
||||
? String(state?.mailProvider || '163').trim()
|
||||
: (String(state?.emailGenerator || '').trim().toLowerCase() === 'custom'
|
||||
|| String(state?.emailGenerator || '').trim().toLowerCase() === 'manual'
|
||||
@@ -8108,6 +8154,8 @@ function applySettingsState(state) {
|
||||
selectEmailGenerator.value = 'cloudflare';
|
||||
} else if (restoredEmailGenerator === 'cloudflare-temp-email') {
|
||||
selectEmailGenerator.value = 'cloudflare-temp-email';
|
||||
} else if (restoredEmailGenerator === 'cloudmail') {
|
||||
selectEmailGenerator.value = 'cloudmail';
|
||||
} else {
|
||||
selectEmailGenerator.value = 'duck';
|
||||
}
|
||||
@@ -8163,6 +8211,9 @@ function applySettingsState(state) {
|
||||
selectLuckmailEmailType.value = normalizeLuckmailEmailType(state?.luckmailEmailType);
|
||||
inputLuckmailDomain.value = state?.luckmailDomain || '';
|
||||
applyCloudflareTempEmailSettingsState(state);
|
||||
if (typeof applyCloudMailSettingsState === 'function') {
|
||||
applyCloudMailSettingsState(state);
|
||||
}
|
||||
renderCloudflareDomainOptions(state?.cloudflareDomain || '');
|
||||
setCloudflareDomainEditMode(false, { clearInput: true });
|
||||
inputAutoSkipFailures.checked = Boolean(state?.autoRunSkipFailures);
|
||||
@@ -8906,6 +8957,7 @@ function getSelectedEmailGenerator() {
|
||||
}
|
||||
if (generator === 'cloudflare') return 'cloudflare';
|
||||
if (generator === 'cloudflare-temp-email') return 'cloudflare-temp-email';
|
||||
if (generator === 'cloudmail') return 'cloudmail';
|
||||
return 'duck';
|
||||
}
|
||||
|
||||
@@ -8953,6 +9005,14 @@ function getEmailGeneratorUiCopy() {
|
||||
label: 'Cloudflare Temp Email',
|
||||
};
|
||||
}
|
||||
if (getSelectedEmailGenerator() === 'cloudmail') {
|
||||
return {
|
||||
buttonLabel: '生成',
|
||||
placeholder: '点击生成 Cloud Mail 邮箱,或手动粘贴邮箱',
|
||||
successVerb: '生成',
|
||||
label: 'Cloud Mail',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
buttonLabel: '获取',
|
||||
@@ -9352,6 +9412,7 @@ function updateMailProviderUI() {
|
||||
const useIcloudProvider = isIcloudMailProvider();
|
||||
const useEmailGenerator = !useHotmail && !useLuckmail && !useCustomEmail && (!useGeneratedAlias || useGmail);
|
||||
const useCloudflareTempEmailProvider = selectMailProvider.value === 'cloudflare-temp-email';
|
||||
const useCloudMailProvider = selectMailProvider.value === 'cloudmail';
|
||||
const aliasUiCopy = useGeneratedAlias
|
||||
? getManagedAliasProviderUiCopy(selectMailProvider.value, mail2925Mode)
|
||||
: null;
|
||||
@@ -9374,9 +9435,13 @@ function updateMailProviderUI() {
|
||||
const useCloudflare = selectedGenerator === 'cloudflare';
|
||||
const useIcloud = selectedGenerator === 'icloud';
|
||||
const useCloudflareTempEmailGenerator = selectedGenerator === 'cloudflare-temp-email';
|
||||
const useCloudMailGenerator = selectedGenerator === 'cloudmail';
|
||||
const showCloudflareDomain = useEmailGenerator && useCloudflare;
|
||||
const showCloudflareTempEmailSettings = useCloudflareTempEmailProvider || (useEmailGenerator && useCloudflareTempEmailGenerator);
|
||||
const showCloudflareTempEmailReceiveMailbox = useCloudflareTempEmailProvider && !useCloudflareTempEmailGenerator;
|
||||
const showCloudMailSettings = useCloudMailProvider || (useEmailGenerator && useCloudMailGenerator);
|
||||
const showCloudMailReceiveMailbox = useCloudMailProvider && !useCloudMailGenerator;
|
||||
const showCloudMailDomain = useEmailGenerator && useCloudMailGenerator;
|
||||
const selectedIcloudHost = typeof getSelectedIcloudHostPreference === 'function'
|
||||
? getSelectedIcloudHostPreference()
|
||||
: (normalizeIcloudHostValue(icloudHostPreferenceValue || latestState?.icloudHostPreference || '')
|
||||
@@ -9402,6 +9467,14 @@ function updateMailProviderUI() {
|
||||
if (cloudflareTempEmailSection) {
|
||||
cloudflareTempEmailSection.style.display = showCloudflareTempEmailSettings ? '' : 'none';
|
||||
}
|
||||
if (typeof cloudMailSection !== 'undefined' && cloudMailSection) {
|
||||
cloudMailSection.style.display = showCloudMailSettings ? '' : 'none';
|
||||
}
|
||||
if (typeof rowCloudMailBaseUrl !== 'undefined' && rowCloudMailBaseUrl) rowCloudMailBaseUrl.style.display = showCloudMailSettings ? '' : 'none';
|
||||
if (typeof rowCloudMailAdminEmail !== 'undefined' && rowCloudMailAdminEmail) rowCloudMailAdminEmail.style.display = showCloudMailSettings ? '' : 'none';
|
||||
if (typeof rowCloudMailAdminPassword !== 'undefined' && rowCloudMailAdminPassword) rowCloudMailAdminPassword.style.display = showCloudMailSettings ? '' : 'none';
|
||||
if (typeof rowCloudMailReceiveMailbox !== 'undefined' && rowCloudMailReceiveMailbox) rowCloudMailReceiveMailbox.style.display = showCloudMailReceiveMailbox ? '' : 'none';
|
||||
if (typeof rowCloudMailDomain !== 'undefined' && rowCloudMailDomain) rowCloudMailDomain.style.display = showCloudMailDomain ? '' : 'none';
|
||||
if (icloudSection) {
|
||||
const showIcloudSection = (useEmailGenerator && useIcloud) || useIcloudProvider;
|
||||
icloudSection.style.display = showIcloudSection ? '' : 'none';
|
||||
@@ -13272,6 +13345,21 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
|
||||
) {
|
||||
updateMailProviderUI();
|
||||
}
|
||||
if (message.payload.cloudMailBaseUrl !== undefined && inputCloudMailBaseUrl) {
|
||||
inputCloudMailBaseUrl.value = message.payload.cloudMailBaseUrl || '';
|
||||
}
|
||||
if (message.payload.cloudMailAdminEmail !== undefined && inputCloudMailAdminEmail) {
|
||||
inputCloudMailAdminEmail.value = message.payload.cloudMailAdminEmail || '';
|
||||
}
|
||||
if (message.payload.cloudMailAdminPassword !== undefined && inputCloudMailAdminPassword) {
|
||||
inputCloudMailAdminPassword.value = message.payload.cloudMailAdminPassword || '';
|
||||
}
|
||||
if (message.payload.cloudMailReceiveMailbox !== undefined && inputCloudMailReceiveMailbox) {
|
||||
inputCloudMailReceiveMailbox.value = message.payload.cloudMailReceiveMailbox || '';
|
||||
}
|
||||
if (message.payload.cloudMailDomain !== undefined && inputCloudMailDomain) {
|
||||
inputCloudMailDomain.value = message.payload.cloudMailDomain || '';
|
||||
}
|
||||
if (message.payload.plusModeEnabled !== undefined && inputPlusModeEnabled) {
|
||||
inputPlusModeEnabled.checked = Boolean(message.payload.plusModeEnabled);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user