feat: add custom email pool mail compatibility
This commit is contained in:
+121
-1
@@ -139,10 +139,12 @@ const ICLOUD_LOGIN_URLS = [
|
|||||||
];
|
];
|
||||||
const ICLOUD_PROVIDER = 'icloud';
|
const ICLOUD_PROVIDER = 'icloud';
|
||||||
const GMAIL_PROVIDER = 'gmail';
|
const GMAIL_PROVIDER = 'gmail';
|
||||||
|
const GMAIL_ALIAS_GENERATOR = 'gmail-alias';
|
||||||
const HOTMAIL_PROVIDER = 'hotmail-api';
|
const HOTMAIL_PROVIDER = 'hotmail-api';
|
||||||
const LUCKMAIL_PROVIDER = 'luckmail-api';
|
const LUCKMAIL_PROVIDER = 'luckmail-api';
|
||||||
const CLOUDFLARE_TEMP_EMAIL_PROVIDER = 'cloudflare-temp-email';
|
const CLOUDFLARE_TEMP_EMAIL_PROVIDER = 'cloudflare-temp-email';
|
||||||
const CLOUDFLARE_TEMP_EMAIL_GENERATOR = 'cloudflare-temp-email';
|
const CLOUDFLARE_TEMP_EMAIL_GENERATOR = 'cloudflare-temp-email';
|
||||||
|
const CUSTOM_EMAIL_POOL_GENERATOR = 'custom-pool';
|
||||||
const HOTMAIL_MAILBOXES = ['INBOX', 'Junk'];
|
const HOTMAIL_MAILBOXES = ['INBOX', 'Junk'];
|
||||||
const STOP_ERROR_MESSAGE = '流程已被用户停止。';
|
const STOP_ERROR_MESSAGE = '流程已被用户停止。';
|
||||||
const CLOUDFLARE_SECURITY_BLOCK_ERROR_PREFIX = 'CF_SECURITY_BLOCKED::';
|
const CLOUDFLARE_SECURITY_BLOCK_ERROR_PREFIX = 'CF_SECURITY_BLOCKED::';
|
||||||
@@ -263,6 +265,7 @@ const PERSISTED_SETTING_DEFAULTS = {
|
|||||||
mail2925Mode: DEFAULT_MAIL_2925_MODE,
|
mail2925Mode: DEFAULT_MAIL_2925_MODE,
|
||||||
mail2925UseAccountPool: false,
|
mail2925UseAccountPool: false,
|
||||||
emailGenerator: 'duck',
|
emailGenerator: 'duck',
|
||||||
|
customEmailPool: [],
|
||||||
autoDeleteUsedIcloudAlias: false,
|
autoDeleteUsedIcloudAlias: false,
|
||||||
icloudHostPreference: 'auto',
|
icloudHostPreference: 'auto',
|
||||||
accountRunHistoryTextEnabled: false,
|
accountRunHistoryTextEnabled: false,
|
||||||
@@ -640,9 +643,21 @@ function getAutoRunTimerStatusPayload(plan) {
|
|||||||
|
|
||||||
function normalizeEmailGenerator(value = '') {
|
function normalizeEmailGenerator(value = '') {
|
||||||
const normalized = String(value || '').trim().toLowerCase();
|
const normalized = String(value || '').trim().toLowerCase();
|
||||||
|
const customEmailPoolGenerator = typeof CUSTOM_EMAIL_POOL_GENERATOR === 'string'
|
||||||
|
? CUSTOM_EMAIL_POOL_GENERATOR
|
||||||
|
: 'custom-pool';
|
||||||
|
const gmailAliasGenerator = typeof GMAIL_ALIAS_GENERATOR === 'string'
|
||||||
|
? GMAIL_ALIAS_GENERATOR
|
||||||
|
: 'gmail-alias';
|
||||||
if (normalized === 'custom' || normalized === 'manual') {
|
if (normalized === 'custom' || normalized === 'manual') {
|
||||||
return 'custom';
|
return 'custom';
|
||||||
}
|
}
|
||||||
|
if (normalized === gmailAliasGenerator) {
|
||||||
|
return gmailAliasGenerator;
|
||||||
|
}
|
||||||
|
if (normalized === customEmailPoolGenerator) {
|
||||||
|
return customEmailPoolGenerator;
|
||||||
|
}
|
||||||
if (normalized === 'icloud') {
|
if (normalized === 'icloud') {
|
||||||
return 'icloud';
|
return 'icloud';
|
||||||
}
|
}
|
||||||
@@ -651,6 +666,36 @@ function normalizeEmailGenerator(value = '') {
|
|||||||
return 'duck';
|
return 'duck';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeCustomEmailPool(value = []) {
|
||||||
|
const source = Array.isArray(value)
|
||||||
|
? value
|
||||||
|
: String(value || '').split(/[\r\n,,;;]+/);
|
||||||
|
|
||||||
|
return source
|
||||||
|
.map((item) => String(item || '').trim().toLowerCase())
|
||||||
|
.filter((item) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
function isCustomEmailPoolGenerator(stateOrValue = {}) {
|
||||||
|
const generator = typeof stateOrValue === 'string'
|
||||||
|
? stateOrValue
|
||||||
|
: stateOrValue?.emailGenerator;
|
||||||
|
const customEmailPoolGenerator = typeof CUSTOM_EMAIL_POOL_GENERATOR === 'string'
|
||||||
|
? CUSTOM_EMAIL_POOL_GENERATOR
|
||||||
|
: 'custom-pool';
|
||||||
|
return normalizeEmailGenerator(generator) === customEmailPoolGenerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCustomEmailPool(state = {}) {
|
||||||
|
return normalizeCustomEmailPool(state?.customEmailPool);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCustomEmailPoolEmailForRun(state = {}, targetRun = 1) {
|
||||||
|
const entries = getCustomEmailPool(state);
|
||||||
|
const numericRun = Math.max(1, Math.floor(Number(targetRun) || 1));
|
||||||
|
return entries[numericRun - 1] || '';
|
||||||
|
}
|
||||||
|
|
||||||
function normalizePanelMode(value = '') {
|
function normalizePanelMode(value = '') {
|
||||||
return String(value || '').trim().toLowerCase() === 'sub2api' ? 'sub2api' : 'cpa';
|
return String(value || '').trim().toLowerCase() === 'sub2api' ? 'sub2api' : 'cpa';
|
||||||
}
|
}
|
||||||
@@ -894,6 +939,8 @@ function normalizePersistentSettingValue(key, value) {
|
|||||||
return Boolean(value);
|
return Boolean(value);
|
||||||
case 'emailGenerator':
|
case 'emailGenerator':
|
||||||
return normalizeEmailGenerator(value);
|
return normalizeEmailGenerator(value);
|
||||||
|
case 'customEmailPool':
|
||||||
|
return normalizeCustomEmailPool(value);
|
||||||
case 'autoDeleteUsedIcloudAlias':
|
case 'autoDeleteUsedIcloudAlias':
|
||||||
case 'accountRunHistoryTextEnabled':
|
case 'accountRunHistoryTextEnabled':
|
||||||
return Boolean(value);
|
return Boolean(value);
|
||||||
@@ -2130,6 +2177,18 @@ function parseGmailBaseEmail(rawValue) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isGeneratedAliasProvider(stateOrProvider, mail2925Mode = undefined) {
|
function isGeneratedAliasProvider(stateOrProvider, mail2925Mode = undefined) {
|
||||||
|
if (
|
||||||
|
stateOrProvider
|
||||||
|
&& typeof stateOrProvider === 'object'
|
||||||
|
&& !Array.isArray(stateOrProvider)
|
||||||
|
&& normalizeEmailGenerator(stateOrProvider.emailGenerator) === (
|
||||||
|
typeof CUSTOM_EMAIL_POOL_GENERATOR === 'string'
|
||||||
|
? CUSTOM_EMAIL_POOL_GENERATOR
|
||||||
|
: 'custom-pool'
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
const provider = typeof stateOrProvider === 'string'
|
const provider = typeof stateOrProvider === 'string'
|
||||||
? stateOrProvider
|
? stateOrProvider
|
||||||
: stateOrProvider?.mailProvider;
|
: stateOrProvider?.mailProvider;
|
||||||
@@ -2287,6 +2346,18 @@ function getManagedAliasBaseEmail(state = {}, provider = state?.mailProvider) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isGeneratedAliasProvider(stateOrProvider, mail2925Mode = undefined) {
|
function isGeneratedAliasProvider(stateOrProvider, mail2925Mode = undefined) {
|
||||||
|
if (
|
||||||
|
stateOrProvider
|
||||||
|
&& typeof stateOrProvider === 'object'
|
||||||
|
&& !Array.isArray(stateOrProvider)
|
||||||
|
&& normalizeEmailGenerator(stateOrProvider.emailGenerator) === (
|
||||||
|
typeof CUSTOM_EMAIL_POOL_GENERATOR === 'string'
|
||||||
|
? CUSTOM_EMAIL_POOL_GENERATOR
|
||||||
|
: 'custom-pool'
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
const provider = typeof stateOrProvider === 'string'
|
const provider = typeof stateOrProvider === 'string'
|
||||||
? stateOrProvider
|
? stateOrProvider
|
||||||
: stateOrProvider?.mailProvider;
|
: stateOrProvider?.mailProvider;
|
||||||
@@ -4999,7 +5070,12 @@ async function handleStepData(step, payload) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
await finalizeIcloudAliasAfterSuccessfulFlow(latestState);
|
await finalizeIcloudAliasAfterSuccessfulFlow(latestState);
|
||||||
if (shouldUseCustomRegistrationEmail(latestState) && latestState.email) {
|
const shouldClearCustomPoolEmail = String(latestState?.emailGenerator || '').trim().toLowerCase() === (
|
||||||
|
typeof CUSTOM_EMAIL_POOL_GENERATOR === 'string'
|
||||||
|
? CUSTOM_EMAIL_POOL_GENERATOR
|
||||||
|
: 'custom-pool'
|
||||||
|
);
|
||||||
|
if ((shouldUseCustomRegistrationEmail(latestState) || shouldClearCustomPoolEmail) && latestState.email) {
|
||||||
await setEmailStateSilently(null);
|
await setEmailStateSilently(null);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -5413,9 +5489,21 @@ async function executeStepAndWait(step, delayAfter = 2000) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getEmailGeneratorLabel(generator) {
|
function getEmailGeneratorLabel(generator) {
|
||||||
|
const customEmailPoolGenerator = typeof CUSTOM_EMAIL_POOL_GENERATOR === 'string'
|
||||||
|
? CUSTOM_EMAIL_POOL_GENERATOR
|
||||||
|
: 'custom-pool';
|
||||||
|
const gmailAliasGenerator = typeof GMAIL_ALIAS_GENERATOR === 'string'
|
||||||
|
? GMAIL_ALIAS_GENERATOR
|
||||||
|
: 'gmail-alias';
|
||||||
if (generator === 'custom') {
|
if (generator === 'custom') {
|
||||||
return '自定义邮箱';
|
return '自定义邮箱';
|
||||||
}
|
}
|
||||||
|
if (generator === gmailAliasGenerator) {
|
||||||
|
return 'Gmail +tag 邮箱';
|
||||||
|
}
|
||||||
|
if (generator === customEmailPoolGenerator) {
|
||||||
|
return '自定义邮箱池';
|
||||||
|
}
|
||||||
if (generator === 'icloud') {
|
if (generator === 'icloud') {
|
||||||
return 'iCloud 隐私邮箱';
|
return 'iCloud 隐私邮箱';
|
||||||
}
|
}
|
||||||
@@ -5515,11 +5603,13 @@ const generatedEmailHelpers = self.MultiPageGeneratedEmailHelpers?.createGenerat
|
|||||||
buildGeneratedAliasEmail,
|
buildGeneratedAliasEmail,
|
||||||
buildCloudflareTempEmailHeaders,
|
buildCloudflareTempEmailHeaders,
|
||||||
CLOUDFLARE_TEMP_EMAIL_GENERATOR,
|
CLOUDFLARE_TEMP_EMAIL_GENERATOR,
|
||||||
|
CUSTOM_EMAIL_POOL_GENERATOR,
|
||||||
DUCK_AUTOFILL_URL,
|
DUCK_AUTOFILL_URL,
|
||||||
fetch,
|
fetch,
|
||||||
fetchIcloudHideMyEmail,
|
fetchIcloudHideMyEmail,
|
||||||
getCloudflareTempEmailAddressFromResponse,
|
getCloudflareTempEmailAddressFromResponse,
|
||||||
getCloudflareTempEmailConfig,
|
getCloudflareTempEmailConfig,
|
||||||
|
getCustomEmailPoolEmail: getCustomEmailPoolEmailForRun,
|
||||||
getState,
|
getState,
|
||||||
ensureMail2925AccountForFlow,
|
ensureMail2925AccountForFlow,
|
||||||
joinCloudflareTempEmailUrl,
|
joinCloudflareTempEmailUrl,
|
||||||
@@ -5762,6 +5852,21 @@ async function ensureAutoEmailReady(targetRun, totalRuns, attemptRuns) {
|
|||||||
return currentState.email;
|
return currentState.email;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isCustomEmailPoolGenerator(currentState)) {
|
||||||
|
const queuedEmail = getCustomEmailPoolEmailForRun(currentState, targetRun);
|
||||||
|
if (!queuedEmail) {
|
||||||
|
const poolSize = getCustomEmailPool(currentState).length;
|
||||||
|
throw new Error(
|
||||||
|
poolSize > 0
|
||||||
|
? `自定义邮箱池第 ${targetRun} 个邮箱不存在,请检查邮箱池数量是否与自动轮数一致。`
|
||||||
|
: '自定义邮箱池为空,请先至少填写 1 个邮箱。'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await setEmailState(queuedEmail);
|
||||||
|
await addLog(`=== 目标 ${targetRun}/${totalRuns} 轮:自定义邮箱池已就绪:${queuedEmail}(第 ${attemptRuns} 次尝试)===`, 'ok');
|
||||||
|
return queuedEmail;
|
||||||
|
}
|
||||||
|
|
||||||
if (shouldUseCustomRegistrationEmail(currentState)) {
|
if (shouldUseCustomRegistrationEmail(currentState)) {
|
||||||
await addLog(`=== 目标 ${targetRun}/${totalRuns} 轮已暂停:请先填写自定义注册邮箱,然后继续 ===`, 'warn');
|
await addLog(`=== 目标 ${targetRun}/${totalRuns} 轮已暂停:请先填写自定义注册邮箱,然后继续 ===`, 'warn');
|
||||||
await broadcastAutoRunStatus('waiting_email', {
|
await broadcastAutoRunStatus('waiting_email', {
|
||||||
@@ -5880,6 +5985,21 @@ async function ensureAutoEmailReady(targetRun, totalRuns, attemptRuns) {
|
|||||||
return currentState.email;
|
return currentState.email;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isCustomEmailPoolGenerator(currentState)) {
|
||||||
|
const queuedEmail = getCustomEmailPoolEmailForRun(currentState, targetRun);
|
||||||
|
if (!queuedEmail) {
|
||||||
|
const poolSize = getCustomEmailPool(currentState).length;
|
||||||
|
throw new Error(
|
||||||
|
poolSize > 0
|
||||||
|
? `自定义邮箱池第 ${targetRun} 个邮箱不存在,请检查邮箱池数量是否与自动轮数一致。`
|
||||||
|
: '自定义邮箱池为空,请先至少填写 1 个邮箱。'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await setEmailState(queuedEmail);
|
||||||
|
await addLog(`=== 目标 ${targetRun}/${totalRuns} 轮:自定义邮箱池已就绪:${queuedEmail}(第 ${attemptRuns} 次尝试)===`, 'ok');
|
||||||
|
return queuedEmail;
|
||||||
|
}
|
||||||
|
|
||||||
if (shouldUseCustomRegistrationEmail(currentState)) {
|
if (shouldUseCustomRegistrationEmail(currentState)) {
|
||||||
await addLog(`=== 目标 ${targetRun}/${totalRuns} 轮已暂停:请先填写自定义注册邮箱,然后继续 ===`, 'warn');
|
await addLog(`=== 目标 ${targetRun}/${totalRuns} 轮已暂停:请先填写自定义注册邮箱,然后继续 ===`, 'warn');
|
||||||
await broadcastAutoRunStatus('waiting_email', {
|
await broadcastAutoRunStatus('waiting_email', {
|
||||||
|
|||||||
@@ -7,11 +7,13 @@
|
|||||||
buildGeneratedAliasEmail,
|
buildGeneratedAliasEmail,
|
||||||
buildCloudflareTempEmailHeaders,
|
buildCloudflareTempEmailHeaders,
|
||||||
CLOUDFLARE_TEMP_EMAIL_GENERATOR,
|
CLOUDFLARE_TEMP_EMAIL_GENERATOR,
|
||||||
|
CUSTOM_EMAIL_POOL_GENERATOR,
|
||||||
DUCK_AUTOFILL_URL,
|
DUCK_AUTOFILL_URL,
|
||||||
fetch,
|
fetch,
|
||||||
fetchIcloudHideMyEmail,
|
fetchIcloudHideMyEmail,
|
||||||
getCloudflareTempEmailAddressFromResponse,
|
getCloudflareTempEmailAddressFromResponse,
|
||||||
getCloudflareTempEmailConfig,
|
getCloudflareTempEmailConfig,
|
||||||
|
getCustomEmailPoolEmail,
|
||||||
getState,
|
getState,
|
||||||
ensureMail2925AccountForFlow,
|
ensureMail2925AccountForFlow,
|
||||||
joinCloudflareTempEmailUrl,
|
joinCloudflareTempEmailUrl,
|
||||||
@@ -188,6 +190,24 @@
|
|||||||
return result.email;
|
return result.email;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function fetchCustomEmailPoolEmail(state, options = {}) {
|
||||||
|
throwIfStopped();
|
||||||
|
const latestState = state || await getState();
|
||||||
|
const requestedIndex = Math.max(0, Math.floor(Number(options.poolIndex) || 0));
|
||||||
|
const email = String(getCustomEmailPoolEmail?.(latestState, requestedIndex + 1) || '').trim().toLowerCase();
|
||||||
|
if (!email) {
|
||||||
|
throw new Error(
|
||||||
|
requestedIndex > 0
|
||||||
|
? `自定义邮箱池第 ${requestedIndex + 1} 个邮箱不存在,请检查邮箱池配置。`
|
||||||
|
: '自定义邮箱池为空,请先至少填写 1 个邮箱。'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await setEmailState(email);
|
||||||
|
await addLog(`自定义邮箱池:已取用 ${email}`, 'ok');
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
async function fetchManagedAliasEmail(state, options = {}) {
|
async function fetchManagedAliasEmail(state, options = {}) {
|
||||||
throwIfStopped();
|
throwIfStopped();
|
||||||
const provider = String(options.mailProvider || state?.mailProvider || '').trim().toLowerCase();
|
const provider = String(options.mailProvider || state?.mailProvider || '').trim().toLowerCase();
|
||||||
@@ -233,13 +253,19 @@
|
|||||||
const mail2925Mode = options.mail2925Mode !== undefined
|
const mail2925Mode = options.mail2925Mode !== undefined
|
||||||
? options.mail2925Mode
|
? options.mail2925Mode
|
||||||
: currentState.mail2925Mode;
|
: currentState.mail2925Mode;
|
||||||
if (isGeneratedAliasProvider?.(provider, mail2925Mode)) {
|
|
||||||
return fetchManagedAliasEmail(currentState, options);
|
|
||||||
}
|
|
||||||
const generator = normalizeEmailGenerator(options.generator ?? currentState.emailGenerator);
|
const generator = normalizeEmailGenerator(options.generator ?? currentState.emailGenerator);
|
||||||
if (generator === 'custom') {
|
if (generator === 'custom') {
|
||||||
throw new Error('当前邮箱生成方式为自定义邮箱,请直接填写注册邮箱。');
|
throw new Error('当前邮箱生成方式为自定义邮箱,请直接填写注册邮箱。');
|
||||||
}
|
}
|
||||||
|
if (generator === CUSTOM_EMAIL_POOL_GENERATOR) {
|
||||||
|
return fetchCustomEmailPoolEmail(currentState, options);
|
||||||
|
}
|
||||||
|
const shouldUseManagedAlias = typeof isGeneratedAliasProvider === 'function'
|
||||||
|
? isGeneratedAliasProvider(currentState, mail2925Mode)
|
||||||
|
: false;
|
||||||
|
if (shouldUseManagedAlias) {
|
||||||
|
return fetchManagedAliasEmail(currentState, options);
|
||||||
|
}
|
||||||
if (generator === 'icloud') {
|
if (generator === 'icloud') {
|
||||||
return fetchIcloudHideMyEmail();
|
return fetchIcloudHideMyEmail();
|
||||||
}
|
}
|
||||||
@@ -255,6 +281,7 @@
|
|||||||
return {
|
return {
|
||||||
ensureCloudflareTempEmailConfig,
|
ensureCloudflareTempEmailConfig,
|
||||||
fetchCloudflareEmail,
|
fetchCloudflareEmail,
|
||||||
|
fetchCustomEmailPoolEmail,
|
||||||
fetchCloudflareTempEmailAddress,
|
fetchCloudflareTempEmailAddress,
|
||||||
fetchDuckEmail,
|
fetchDuckEmail,
|
||||||
fetchGeneratedEmail,
|
fetchGeneratedEmail,
|
||||||
|
|||||||
@@ -229,12 +229,19 @@
|
|||||||
<div class="data-row" id="row-email-generator">
|
<div class="data-row" id="row-email-generator">
|
||||||
<span class="data-label">邮箱生成</span>
|
<span class="data-label">邮箱生成</span>
|
||||||
<select id="select-email-generator" class="data-select">
|
<select id="select-email-generator" class="data-select">
|
||||||
|
<option value="gmail-alias">Gmail +tag</option>
|
||||||
<option value="duck">DuckDuckGo</option>
|
<option value="duck">DuckDuckGo</option>
|
||||||
|
<option value="custom-pool">自定义邮箱池</option>
|
||||||
<option value="cloudflare">Cloudflare</option>
|
<option value="cloudflare">Cloudflare</option>
|
||||||
<option value="icloud">iCloud 隐私邮箱</option>
|
<option value="icloud">iCloud 隐私邮箱</option>
|
||||||
<option value="cloudflare-temp-email">Cloudflare Temp Email</option>
|
<option value="cloudflare-temp-email">Cloudflare Temp Email</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="data-row data-check-row" id="row-custom-email-pool" style="display:none;">
|
||||||
|
<span class="data-label">邮箱池</span>
|
||||||
|
<textarea id="input-custom-email-pool" class="data-textarea"
|
||||||
|
placeholder="每行一个邮箱,例如 alias001@gmail.com alias002@gmail.com"></textarea>
|
||||||
|
</div>
|
||||||
<div class="data-row" id="row-temp-email-base-url" style="display:none;">
|
<div class="data-row" id="row-temp-email-base-url" style="display:none;">
|
||||||
<span class="data-label">Temp API</span>
|
<span class="data-label">Temp API</span>
|
||||||
<input type="text" id="input-temp-email-base-url" class="data-input" placeholder="https://your-worker-domain" />
|
<input type="text" id="input-temp-email-base-url" class="data-input" placeholder="https://your-worker-domain" />
|
||||||
|
|||||||
+158
-17
@@ -102,6 +102,8 @@ const rowMail2925PoolSettings = document.getElementById('row-mail2925-pool-setti
|
|||||||
const mail2925ModeButtons = Array.from(document.querySelectorAll('[data-mail2925-mode]'));
|
const mail2925ModeButtons = Array.from(document.querySelectorAll('[data-mail2925-mode]'));
|
||||||
const rowEmailGenerator = document.getElementById('row-email-generator');
|
const rowEmailGenerator = document.getElementById('row-email-generator');
|
||||||
const selectEmailGenerator = document.getElementById('select-email-generator');
|
const selectEmailGenerator = document.getElementById('select-email-generator');
|
||||||
|
const rowCustomEmailPool = document.getElementById('row-custom-email-pool');
|
||||||
|
const inputCustomEmailPool = document.getElementById('input-custom-email-pool');
|
||||||
const rowTempEmailBaseUrl = document.getElementById('row-temp-email-base-url');
|
const rowTempEmailBaseUrl = document.getElementById('row-temp-email-base-url');
|
||||||
const inputTempEmailBaseUrl = document.getElementById('input-temp-email-base-url');
|
const inputTempEmailBaseUrl = document.getElementById('input-temp-email-base-url');
|
||||||
const rowTempEmailAdminAuth = document.getElementById('row-temp-email-admin-auth');
|
const rowTempEmailAdminAuth = document.getElementById('row-temp-email-admin-auth');
|
||||||
@@ -254,7 +256,9 @@ const HOTMAIL_SERVICE_MODE_REMOTE = 'remote';
|
|||||||
const HOTMAIL_SERVICE_MODE_LOCAL = 'local';
|
const HOTMAIL_SERVICE_MODE_LOCAL = 'local';
|
||||||
const ICLOUD_PROVIDER = 'icloud';
|
const ICLOUD_PROVIDER = 'icloud';
|
||||||
const GMAIL_PROVIDER = 'gmail';
|
const GMAIL_PROVIDER = 'gmail';
|
||||||
|
const GMAIL_ALIAS_GENERATOR = 'gmail-alias';
|
||||||
const LUCKMAIL_PROVIDER = 'luckmail-api';
|
const LUCKMAIL_PROVIDER = 'luckmail-api';
|
||||||
|
const CUSTOM_EMAIL_POOL_GENERATOR = 'custom-pool';
|
||||||
const DEFAULT_LUCKMAIL_BASE_URL = 'https://mails.luckyous.com';
|
const DEFAULT_LUCKMAIL_BASE_URL = 'https://mails.luckyous.com';
|
||||||
const DEFAULT_LUCKMAIL_EMAIL_TYPE = 'ms_graph';
|
const DEFAULT_LUCKMAIL_EMAIL_TYPE = 'ms_graph';
|
||||||
const DISPLAY_TIMEZONE = 'Asia/Shanghai';
|
const DISPLAY_TIMEZONE = 'Asia/Shanghai';
|
||||||
@@ -463,14 +467,14 @@ function getCurrentRegistrationEmailUiCopy() {
|
|||||||
if (isCustomMailProvider()) {
|
if (isCustomMailProvider()) {
|
||||||
return getCustomMailProviderUiCopy();
|
return getCustomMailProviderUiCopy();
|
||||||
}
|
}
|
||||||
if (isManagedAliasProvider()) {
|
if (usesGeneratedAliasMailProvider()) {
|
||||||
return getManagedAliasProviderUiCopy();
|
return getManagedAliasProviderUiCopy();
|
||||||
}
|
}
|
||||||
return getEmailGeneratorUiCopy();
|
return getEmailGeneratorUiCopy();
|
||||||
}
|
}
|
||||||
|
|
||||||
function isCurrentRegistrationEmailCompatible(email = inputEmail.value.trim(), provider = selectMailProvider.value, state = latestState) {
|
function isCurrentRegistrationEmailCompatible(email = inputEmail.value.trim(), provider = selectMailProvider.value, state = latestState) {
|
||||||
if (!isManagedAliasProvider(provider) || !email) {
|
if (!usesGeneratedAliasMailProvider(provider, getSelectedMail2925Mode()) || !email) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const baseEmail = getManagedAliasBaseEmailForProvider(provider, state);
|
const baseEmail = getManagedAliasBaseEmailForProvider(provider, state);
|
||||||
@@ -606,8 +610,19 @@ const LOG_LEVEL_LABELS = {
|
|||||||
error: '错误',
|
error: '错误',
|
||||||
};
|
};
|
||||||
|
|
||||||
function usesGeneratedAliasMailProvider(provider, mail2925Mode = getSelectedMail2925Mode()) {
|
function usesGeneratedAliasMailProvider(
|
||||||
return isManagedAliasProvider(provider, mail2925Mode);
|
provider,
|
||||||
|
mail2925Mode = getSelectedMail2925Mode(),
|
||||||
|
generator = undefined
|
||||||
|
) {
|
||||||
|
const customEmailPoolGenerator = typeof CUSTOM_EMAIL_POOL_GENERATOR === 'string'
|
||||||
|
? CUSTOM_EMAIL_POOL_GENERATOR
|
||||||
|
: 'custom-pool';
|
||||||
|
const resolvedGenerator = generator !== undefined
|
||||||
|
? generator
|
||||||
|
: (typeof getSelectedEmailGenerator === 'function' ? getSelectedEmailGenerator() : '');
|
||||||
|
return resolvedGenerator !== customEmailPoolGenerator
|
||||||
|
&& isManagedAliasProvider(provider, mail2925Mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseGmailBaseEmail(rawValue = '') {
|
function parseGmailBaseEmail(rawValue = '') {
|
||||||
@@ -1173,7 +1188,37 @@ function formatAutoStepDelayInputValue(value) {
|
|||||||
return normalized === null ? '' : String(normalized);
|
return normalized === null ? '' : String(normalized);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeCustomEmailPoolEntries(value = '') {
|
||||||
|
const source = Array.isArray(value)
|
||||||
|
? value
|
||||||
|
: String(value || '').split(/[\r\n,,;;]+/);
|
||||||
|
|
||||||
|
return source
|
||||||
|
.map((item) => String(item || '').trim().toLowerCase())
|
||||||
|
.filter((item) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
function usesCustomEmailPoolGenerator(provider = selectMailProvider.value) {
|
||||||
|
return !isCustomMailProvider(provider)
|
||||||
|
&& !isLuckmailProvider(provider)
|
||||||
|
&& getSelectedEmailGenerator() === CUSTOM_EMAIL_POOL_GENERATOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCustomEmailPoolSize() {
|
||||||
|
return normalizeCustomEmailPoolEntries(inputCustomEmailPool?.value).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncRunCountFromCustomEmailPool() {
|
||||||
|
if (!usesCustomEmailPoolGenerator()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
inputRunCount.value = String(getCustomEmailPoolSize());
|
||||||
|
}
|
||||||
|
|
||||||
function getRunCountValue() {
|
function getRunCountValue() {
|
||||||
|
if (typeof usesCustomEmailPoolGenerator === 'function' && usesCustomEmailPoolGenerator()) {
|
||||||
|
return getCustomEmailPoolSize();
|
||||||
|
}
|
||||||
return Math.max(1, parseInt(inputRunCount.value, 10) || 1);
|
return Math.max(1, parseInt(inputRunCount.value, 10) || 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1486,6 +1531,9 @@ function collectSettingsPayload() {
|
|||||||
mail2925Mode: getSelectedMail2925Mode(),
|
mail2925Mode: getSelectedMail2925Mode(),
|
||||||
mail2925UseAccountPool,
|
mail2925UseAccountPool,
|
||||||
emailGenerator: selectEmailGenerator.value,
|
emailGenerator: selectEmailGenerator.value,
|
||||||
|
customEmailPool: typeof normalizeCustomEmailPoolEntries === 'function'
|
||||||
|
? normalizeCustomEmailPoolEntries(inputCustomEmailPool?.value)
|
||||||
|
: [],
|
||||||
autoDeleteUsedIcloudAlias: checkboxAutoDeleteIcloud?.checked,
|
autoDeleteUsedIcloudAlias: checkboxAutoDeleteIcloud?.checked,
|
||||||
icloudHostPreference: selectIcloudHostPreference?.value || 'auto',
|
icloudHostPreference: selectIcloudHostPreference?.value || 'auto',
|
||||||
...(contributionModeEnabled ? {} : {
|
...(contributionModeEnabled ? {} : {
|
||||||
@@ -1738,10 +1786,11 @@ function applyAutoRunStatus(payload = currentAutoRun) {
|
|||||||
|
|
||||||
setSettingsCardLocked(settingsCardLocked);
|
setSettingsCardLocked(settingsCardLocked);
|
||||||
|
|
||||||
inputRunCount.disabled = currentAutoRun.autoRunning;
|
inputRunCount.disabled = currentAutoRun.autoRunning || usesCustomEmailPoolGenerator();
|
||||||
btnAutoRun.disabled = currentAutoRun.autoRunning;
|
btnAutoRun.disabled = currentAutoRun.autoRunning;
|
||||||
btnFetchEmail.disabled = locked
|
btnFetchEmail.disabled = locked
|
||||||
|| isCustomMailProvider();
|
|| isCustomMailProvider()
|
||||||
|
|| usesCustomEmailPoolGenerator();
|
||||||
inputEmail.disabled = locked;
|
inputEmail.disabled = locked;
|
||||||
inputAutoSkipFailures.disabled = scheduled;
|
inputAutoSkipFailures.disabled = scheduled;
|
||||||
|
|
||||||
@@ -1779,7 +1828,7 @@ function applyAutoRunStatus(payload = currentAutoRun) {
|
|||||||
setDefaultAutoRunButton();
|
setDefaultAutoRunButton();
|
||||||
inputEmail.disabled = false;
|
inputEmail.disabled = false;
|
||||||
if (!locked) {
|
if (!locked) {
|
||||||
btnFetchEmail.disabled = isCustomMailProvider();
|
btnFetchEmail.disabled = isCustomMailProvider() || usesCustomEmailPoolGenerator();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1869,7 +1918,13 @@ function applySettingsState(state) {
|
|||||||
setMail2925Mode(state?.mail2925Mode);
|
setMail2925Mode(state?.mail2925Mode);
|
||||||
{
|
{
|
||||||
const restoredEmailGenerator = String(state?.emailGenerator || '').trim().toLowerCase();
|
const restoredEmailGenerator = String(state?.emailGenerator || '').trim().toLowerCase();
|
||||||
if (restoredEmailGenerator === 'icloud') {
|
if (restoredMailProvider === GMAIL_PROVIDER) {
|
||||||
|
selectEmailGenerator.value = restoredEmailGenerator === CUSTOM_EMAIL_POOL_GENERATOR
|
||||||
|
? CUSTOM_EMAIL_POOL_GENERATOR
|
||||||
|
: GMAIL_ALIAS_GENERATOR;
|
||||||
|
} else if (restoredEmailGenerator === CUSTOM_EMAIL_POOL_GENERATOR) {
|
||||||
|
selectEmailGenerator.value = CUSTOM_EMAIL_POOL_GENERATOR;
|
||||||
|
} else if (restoredEmailGenerator === 'icloud') {
|
||||||
selectEmailGenerator.value = 'icloud';
|
selectEmailGenerator.value = 'icloud';
|
||||||
} else if (restoredEmailGenerator === 'cloudflare') {
|
} else if (restoredEmailGenerator === 'cloudflare') {
|
||||||
selectEmailGenerator.value = 'cloudflare';
|
selectEmailGenerator.value = 'cloudflare';
|
||||||
@@ -1905,6 +1960,9 @@ function applySettingsState(state) {
|
|||||||
setManagedAliasBaseEmailInputForProvider(restoredMailProvider, state);
|
setManagedAliasBaseEmailInputForProvider(restoredMailProvider, state);
|
||||||
inputInbucketHost.value = state?.inbucketHost || '';
|
inputInbucketHost.value = state?.inbucketHost || '';
|
||||||
inputInbucketMailbox.value = state?.inbucketMailbox || '';
|
inputInbucketMailbox.value = state?.inbucketMailbox || '';
|
||||||
|
if (inputCustomEmailPool) {
|
||||||
|
inputCustomEmailPool.value = normalizeCustomEmailPoolEntries(state?.customEmailPool).join('\n');
|
||||||
|
}
|
||||||
setHotmailServiceMode(state?.hotmailServiceMode);
|
setHotmailServiceMode(state?.hotmailServiceMode);
|
||||||
inputHotmailRemoteBaseUrl.value = state?.hotmailRemoteBaseUrl || '';
|
inputHotmailRemoteBaseUrl.value = state?.hotmailRemoteBaseUrl || '';
|
||||||
inputHotmailLocalBaseUrl.value = state?.hotmailLocalBaseUrl || '';
|
inputHotmailLocalBaseUrl.value = state?.hotmailLocalBaseUrl || '';
|
||||||
@@ -2390,6 +2448,12 @@ function getSelectedEmailGenerator() {
|
|||||||
if (generator === 'custom' || generator === 'manual') {
|
if (generator === 'custom' || generator === 'manual') {
|
||||||
return 'custom';
|
return 'custom';
|
||||||
}
|
}
|
||||||
|
if (generator === GMAIL_ALIAS_GENERATOR) {
|
||||||
|
return GMAIL_ALIAS_GENERATOR;
|
||||||
|
}
|
||||||
|
if (generator === CUSTOM_EMAIL_POOL_GENERATOR) {
|
||||||
|
return CUSTOM_EMAIL_POOL_GENERATOR;
|
||||||
|
}
|
||||||
if (generator === 'icloud') {
|
if (generator === 'icloud') {
|
||||||
return 'icloud';
|
return 'icloud';
|
||||||
}
|
}
|
||||||
@@ -2402,6 +2466,22 @@ function getEmailGeneratorUiCopy() {
|
|||||||
if (getSelectedEmailGenerator() === 'custom') {
|
if (getSelectedEmailGenerator() === 'custom') {
|
||||||
return getCustomMailProviderUiCopy();
|
return getCustomMailProviderUiCopy();
|
||||||
}
|
}
|
||||||
|
if (getSelectedEmailGenerator() === GMAIL_ALIAS_GENERATOR) {
|
||||||
|
return {
|
||||||
|
buttonLabel: '生成',
|
||||||
|
placeholder: '步骤 3 自动生成 Gmail +tag 邮箱并回填',
|
||||||
|
successVerb: '生成',
|
||||||
|
label: 'Gmail +tag 邮箱',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (getSelectedEmailGenerator() === CUSTOM_EMAIL_POOL_GENERATOR) {
|
||||||
|
return {
|
||||||
|
buttonLabel: '取下一个',
|
||||||
|
placeholder: '按邮箱池顺序自动回填,也可以手动粘贴当前轮邮箱',
|
||||||
|
successVerb: '取用',
|
||||||
|
label: '自定义邮箱池',
|
||||||
|
};
|
||||||
|
}
|
||||||
if (getSelectedEmailGenerator() === 'icloud') {
|
if (getSelectedEmailGenerator() === 'icloud') {
|
||||||
return {
|
return {
|
||||||
buttonLabel: '获取',
|
buttonLabel: '获取',
|
||||||
@@ -2642,13 +2722,29 @@ function updateMailProviderUI() {
|
|||||||
const useMail2925 = selectMailProvider.value === '2925';
|
const useMail2925 = selectMailProvider.value === '2925';
|
||||||
const useMail2925AccountPool = useMail2925 && Boolean(inputMail2925UseAccountPool?.checked);
|
const useMail2925AccountPool = useMail2925 && Boolean(inputMail2925UseAccountPool?.checked);
|
||||||
const mail2925Mode = getSelectedMail2925Mode();
|
const mail2925Mode = getSelectedMail2925Mode();
|
||||||
const useGeneratedAlias = usesGeneratedAliasMailProvider(selectMailProvider.value, mail2925Mode);
|
const gmailOnlyGenerators = new Set([GMAIL_ALIAS_GENERATOR, CUSTOM_EMAIL_POOL_GENERATOR]);
|
||||||
|
Array.from(selectEmailGenerator?.options || []).forEach((option) => {
|
||||||
|
if (!option) return;
|
||||||
|
if (useGmail) {
|
||||||
|
option.hidden = !gmailOnlyGenerators.has(String(option.value || '').trim().toLowerCase());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
option.hidden = String(option.value || '').trim().toLowerCase() === GMAIL_ALIAS_GENERATOR;
|
||||||
|
});
|
||||||
|
if (useGmail && !gmailOnlyGenerators.has(String(selectEmailGenerator.value || '').trim().toLowerCase())) {
|
||||||
|
selectEmailGenerator.value = GMAIL_ALIAS_GENERATOR;
|
||||||
|
}
|
||||||
|
if (!useGmail && String(selectEmailGenerator.value || '').trim().toLowerCase() === GMAIL_ALIAS_GENERATOR) {
|
||||||
|
selectEmailGenerator.value = 'duck';
|
||||||
|
}
|
||||||
|
const selectedGenerator = getSelectedEmailGenerator();
|
||||||
|
const useGeneratedAlias = usesGeneratedAliasMailProvider(selectMailProvider.value, mail2925Mode, selectedGenerator);
|
||||||
const useInbucket = selectMailProvider.value === 'inbucket';
|
const useInbucket = selectMailProvider.value === 'inbucket';
|
||||||
const useHotmail = selectMailProvider.value === 'hotmail-api';
|
const useHotmail = selectMailProvider.value === 'hotmail-api';
|
||||||
const useLuckmail = isLuckmailProvider();
|
const useLuckmail = isLuckmailProvider();
|
||||||
const useCustomEmail = isCustomMailProvider();
|
const useCustomEmail = isCustomMailProvider();
|
||||||
const useIcloudProvider = isIcloudMailProvider();
|
const useIcloudProvider = isIcloudMailProvider();
|
||||||
const useEmailGenerator = !useHotmail && !useLuckmail && !useGeneratedAlias && !useCustomEmail;
|
const useEmailGenerator = !useHotmail && !useLuckmail && !useCustomEmail && (!useGeneratedAlias || useGmail);
|
||||||
const useCloudflareTempEmailProvider = selectMailProvider.value === 'cloudflare-temp-email';
|
const useCloudflareTempEmailProvider = selectMailProvider.value === 'cloudflare-temp-email';
|
||||||
const aliasUiCopy = useGeneratedAlias
|
const aliasUiCopy = useGeneratedAlias
|
||||||
? getManagedAliasProviderUiCopy(selectMailProvider.value, mail2925Mode)
|
? getManagedAliasProviderUiCopy(selectMailProvider.value, mail2925Mode)
|
||||||
@@ -2665,7 +2761,7 @@ function updateMailProviderUI() {
|
|||||||
const hotmailServiceMode = getSelectedHotmailServiceMode();
|
const hotmailServiceMode = getSelectedHotmailServiceMode();
|
||||||
rowInbucketHost.style.display = useInbucket ? '' : 'none';
|
rowInbucketHost.style.display = useInbucket ? '' : 'none';
|
||||||
rowInbucketMailbox.style.display = useInbucket ? '' : 'none';
|
rowInbucketMailbox.style.display = useInbucket ? '' : 'none';
|
||||||
const selectedGenerator = getSelectedEmailGenerator();
|
const useCustomEmailPool = useEmailGenerator && selectedGenerator === CUSTOM_EMAIL_POOL_GENERATOR;
|
||||||
const useCloudflare = selectedGenerator === 'cloudflare';
|
const useCloudflare = selectedGenerator === 'cloudflare';
|
||||||
const useIcloud = selectedGenerator === 'icloud';
|
const useIcloud = selectedGenerator === 'icloud';
|
||||||
const useCloudflareTempEmailGenerator = selectedGenerator === 'cloudflare-temp-email';
|
const useCloudflareTempEmailGenerator = selectedGenerator === 'cloudflare-temp-email';
|
||||||
@@ -2676,6 +2772,9 @@ function updateMailProviderUI() {
|
|||||||
if (rowEmailGenerator) {
|
if (rowEmailGenerator) {
|
||||||
rowEmailGenerator.style.display = useEmailGenerator ? '' : 'none';
|
rowEmailGenerator.style.display = useEmailGenerator ? '' : 'none';
|
||||||
}
|
}
|
||||||
|
if (rowCustomEmailPool) {
|
||||||
|
rowCustomEmailPool.style.display = useCustomEmailPool ? '' : 'none';
|
||||||
|
}
|
||||||
if (icloudSection) {
|
if (icloudSection) {
|
||||||
const showIcloudSection = (useEmailGenerator && useIcloud) || useIcloudProvider;
|
const showIcloudSection = (useEmailGenerator && useIcloud) || useIcloudProvider;
|
||||||
icloudSection.style.display = showIcloudSection ? '' : 'none';
|
icloudSection.style.display = showIcloudSection ? '' : 'none';
|
||||||
@@ -2726,7 +2825,7 @@ function updateMailProviderUI() {
|
|||||||
}
|
}
|
||||||
inputEmailPrefix.style.display = '';
|
inputEmailPrefix.style.display = '';
|
||||||
inputEmailPrefix.readOnly = false;
|
inputEmailPrefix.readOnly = false;
|
||||||
selectEmailGenerator.disabled = useHotmail || useLuckmail || useGeneratedAlias || useCustomEmail;
|
selectEmailGenerator.disabled = useHotmail || useLuckmail || useCustomEmail || (useGeneratedAlias && !useGmail);
|
||||||
if (useGmail) {
|
if (useGmail) {
|
||||||
labelEmailPrefix.textContent = 'Gmail 原邮箱';
|
labelEmailPrefix.textContent = 'Gmail 原邮箱';
|
||||||
inputEmailPrefix.placeholder = '例如 yourname@gmail.com';
|
inputEmailPrefix.placeholder = '例如 yourname@gmail.com';
|
||||||
@@ -2742,7 +2841,7 @@ function updateMailProviderUI() {
|
|||||||
if (rowHotmailLocalBaseUrl) {
|
if (rowHotmailLocalBaseUrl) {
|
||||||
rowHotmailLocalBaseUrl.style.display = useHotmail && hotmailServiceMode === HOTMAIL_SERVICE_MODE_LOCAL ? '' : 'none';
|
rowHotmailLocalBaseUrl.style.display = useHotmail && hotmailServiceMode === HOTMAIL_SERVICE_MODE_LOCAL ? '' : 'none';
|
||||||
}
|
}
|
||||||
btnFetchEmail.hidden = useHotmail || useLuckmail || useCustomEmail;
|
btnFetchEmail.hidden = useHotmail || useLuckmail || useCustomEmail || useCustomEmailPool;
|
||||||
inputEmail.readOnly = useHotmail || useLuckmail;
|
inputEmail.readOnly = useHotmail || useLuckmail;
|
||||||
inputEmail.placeholder = useHotmail
|
inputEmail.placeholder = useHotmail
|
||||||
? '由 Hotmail 账号池自动分配'
|
? '由 Hotmail 账号池自动分配'
|
||||||
@@ -2755,7 +2854,7 @@ function updateMailProviderUI() {
|
|||||||
if (!useHotmail && !useLuckmail) {
|
if (!useHotmail && !useLuckmail) {
|
||||||
inputEmail.placeholder = uiCopy.placeholder;
|
inputEmail.placeholder = uiCopy.placeholder;
|
||||||
}
|
}
|
||||||
btnFetchEmail.disabled = useLuckmail || useCustomEmail || isAutoRunLockedPhase();
|
btnFetchEmail.disabled = useLuckmail || useCustomEmail || useCustomEmailPool || isAutoRunLockedPhase();
|
||||||
if (!btnFetchEmail.disabled) {
|
if (!btnFetchEmail.disabled) {
|
||||||
btnFetchEmail.textContent = uiCopy.buttonLabel;
|
btnFetchEmail.textContent = uiCopy.buttonLabel;
|
||||||
}
|
}
|
||||||
@@ -2768,20 +2867,25 @@ function updateMailProviderUI() {
|
|||||||
? '步骤 3 会自动生成邮箱,无需手动获取'
|
? '步骤 3 会自动生成邮箱,无需手动获取'
|
||||||
: (useCustomEmail ? '请先填写自定义注册邮箱,成功一轮后会自动清空' : `先自动获取${uiCopy.label},或手动粘贴邮箱后再继续`)));
|
: (useCustomEmail ? '请先填写自定义注册邮箱,成功一轮后会自动清空' : `先自动获取${uiCopy.label},或手动粘贴邮箱后再继续`)));
|
||||||
}
|
}
|
||||||
|
if (autoHintText && useCustomEmailPool) {
|
||||||
|
autoHintText.textContent = getCustomEmailPoolSize() > 0
|
||||||
|
? `当前邮箱池共 ${getCustomEmailPoolSize()} 个邮箱,自动轮数会跟随数量;实际收码仍走当前邮箱服务`
|
||||||
|
: '请先在邮箱池里每行填写一个邮箱,自动轮数会跟随数量';
|
||||||
|
}
|
||||||
if (autoHintText && useGmail && useGeneratedAlias) {
|
if (autoHintText && useGmail && useGeneratedAlias) {
|
||||||
autoHintText.textContent = '请先填写 Gmail 原邮箱,步骤 3 会自动生成 Gmail +tag 地址';
|
autoHintText.textContent = '请先填写 Gmail 原邮箱,步骤 3 会自动生成 Gmail +tag 地址';
|
||||||
}
|
}
|
||||||
if (autoHintText && useGeneratedAlias && aliasUiCopy?.hint) {
|
if (autoHintText && useGeneratedAlias && aliasUiCopy?.hint) {
|
||||||
autoHintText.textContent = aliasUiCopy.hint;
|
autoHintText.textContent = aliasUiCopy.hint;
|
||||||
}
|
}
|
||||||
if (autoHintText && useMail2925AccountPool) {
|
if (autoHintText && useMail2925AccountPool && !useCustomEmailPool) {
|
||||||
autoHintText.textContent = getMail2925Accounts().length
|
autoHintText.textContent = getMail2925Accounts().length
|
||||||
? (useGeneratedAlias
|
? (useGeneratedAlias
|
||||||
? '当前已启用 2925 号池模式,步骤 3 会基于下拉框选中的号池邮箱生成别名地址'
|
? '当前已启用 2925 号池模式,步骤 3 会基于下拉框选中的号池邮箱生成别名地址'
|
||||||
: '当前已启用 2925 号池模式,步骤 4 / 8 遇到登录页时会优先使用下拉框选中的账号自动登录')
|
: '当前已启用 2925 号池模式,步骤 4 / 8 遇到登录页时会优先使用下拉框选中的账号自动登录')
|
||||||
: '当前已启用 2925 号池模式,请先在下方 2925 账号池中添加账号并选择邮箱';
|
: '当前已启用 2925 号池模式,请先在下方 2925 账号池中添加账号并选择邮箱';
|
||||||
}
|
}
|
||||||
if (autoHintText && showCloudflareTempEmailReceiveMailbox) {
|
if (autoHintText && showCloudflareTempEmailReceiveMailbox && !useCustomEmailPool) {
|
||||||
autoHintText.textContent = '若注册邮箱会转发到 Cloudflare Temp Email,请在“邮件接收”中填写实际接收转发邮件的邮箱。';
|
autoHintText.textContent = '若注册邮箱会转发到 Cloudflare Temp Email,请在“邮件接收”中填写实际接收转发邮件的邮箱。';
|
||||||
}
|
}
|
||||||
if (useHotmail) {
|
if (useHotmail) {
|
||||||
@@ -2789,6 +2893,10 @@ function updateMailProviderUI() {
|
|||||||
} else if (useLuckmail) {
|
} else if (useLuckmail) {
|
||||||
inputEmail.value = getCurrentLuckmailEmail();
|
inputEmail.value = getCurrentLuckmailEmail();
|
||||||
}
|
}
|
||||||
|
if (useCustomEmailPool) {
|
||||||
|
syncRunCountFromCustomEmailPool();
|
||||||
|
}
|
||||||
|
inputRunCount.disabled = currentAutoRun.autoRunning || useCustomEmailPool;
|
||||||
renderHotmailAccounts();
|
renderHotmailAccounts();
|
||||||
if (useMail2925) {
|
if (useMail2925) {
|
||||||
renderMail2925Accounts();
|
renderMail2925Accounts();
|
||||||
@@ -3826,7 +3934,22 @@ async function startAutoRunFromCurrentSettings() {
|
|||||||
console.warn('Failed to refresh contribution content hint before auto run:', error);
|
console.warn('Failed to refresh contribution content hint before auto run:', error);
|
||||||
}
|
}
|
||||||
|
|
||||||
const totalRuns = getRunCountValue();
|
if (typeof settingsDirty !== 'undefined' && settingsDirty && typeof saveSettings === 'function') {
|
||||||
|
await saveSettings({ silent: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
const customEmailPoolEnabled = typeof usesCustomEmailPoolGenerator === 'function'
|
||||||
|
&& usesCustomEmailPoolGenerator();
|
||||||
|
const customEmailPoolSize = customEmailPoolEnabled && typeof getCustomEmailPoolSize === 'function'
|
||||||
|
? getCustomEmailPoolSize()
|
||||||
|
: 0;
|
||||||
|
if (customEmailPoolEnabled && customEmailPoolSize <= 0) {
|
||||||
|
throw new Error('请先在邮箱池里至少填写 1 个邮箱。');
|
||||||
|
}
|
||||||
|
const totalRuns = customEmailPoolEnabled ? customEmailPoolSize : getRunCountValue();
|
||||||
|
if (customEmailPoolEnabled) {
|
||||||
|
inputRunCount.value = String(customEmailPoolSize);
|
||||||
|
}
|
||||||
let mode = 'restart';
|
let mode = 'restart';
|
||||||
const autoRunSkipFailures = inputAutoSkipFailures.checked;
|
const autoRunSkipFailures = inputAutoSkipFailures.checked;
|
||||||
const contributionNickname = String(inputContributionNickname?.value || '').trim();
|
const contributionNickname = String(inputContributionNickname?.value || '').trim();
|
||||||
@@ -4282,6 +4405,19 @@ inputEmailPrefix.addEventListener('blur', () => {
|
|||||||
saveSettings({ silent: true }).catch(() => {});
|
saveSettings({ silent: true }).catch(() => {});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
inputCustomEmailPool?.addEventListener('input', () => {
|
||||||
|
syncRunCountFromCustomEmailPool();
|
||||||
|
updateMailProviderUI();
|
||||||
|
markSettingsDirty(true);
|
||||||
|
scheduleSettingsAutoSave();
|
||||||
|
});
|
||||||
|
inputCustomEmailPool?.addEventListener('blur', () => {
|
||||||
|
inputCustomEmailPool.value = normalizeCustomEmailPoolEntries(inputCustomEmailPool.value).join('\n');
|
||||||
|
syncRunCountFromCustomEmailPool();
|
||||||
|
updateMailProviderUI();
|
||||||
|
saveSettings({ silent: true }).catch(() => {});
|
||||||
|
});
|
||||||
|
|
||||||
selectMail2925PoolAccount?.addEventListener('change', async () => {
|
selectMail2925PoolAccount?.addEventListener('change', async () => {
|
||||||
try {
|
try {
|
||||||
await syncSelectedMail2925PoolAccount();
|
await syncSelectedMail2925PoolAccount();
|
||||||
@@ -4332,6 +4468,11 @@ inputRunCount.addEventListener('input', () => {
|
|||||||
updateFallbackThreadIntervalInputState();
|
updateFallbackThreadIntervalInputState();
|
||||||
});
|
});
|
||||||
inputRunCount.addEventListener('blur', () => {
|
inputRunCount.addEventListener('blur', () => {
|
||||||
|
if (usesCustomEmailPoolGenerator()) {
|
||||||
|
syncRunCountFromCustomEmailPool();
|
||||||
|
updateFallbackThreadIntervalInputState();
|
||||||
|
return;
|
||||||
|
}
|
||||||
inputRunCount.value = String(getRunCountValue());
|
inputRunCount.value = String(getRunCountValue());
|
||||||
updateFallbackThreadIntervalInputState();
|
updateFallbackThreadIntervalInputState();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,104 @@
|
|||||||
|
const test = require('node:test');
|
||||||
|
const assert = require('node:assert/strict');
|
||||||
|
const fs = require('node:fs');
|
||||||
|
|
||||||
|
const source = fs.readFileSync('background.js', 'utf8');
|
||||||
|
|
||||||
|
function extractFunction(name) {
|
||||||
|
const markers = [`async function ${name}(`, `function ${name}(`];
|
||||||
|
const start = markers
|
||||||
|
.map((marker) => source.indexOf(marker))
|
||||||
|
.find((index) => index >= 0);
|
||||||
|
if (start < 0) {
|
||||||
|
throw new Error(`missing function ${name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let parenDepth = 0;
|
||||||
|
let signatureEnded = false;
|
||||||
|
let braceStart = -1;
|
||||||
|
for (let i = start; i < source.length; i += 1) {
|
||||||
|
const ch = source[i];
|
||||||
|
if (ch === '(') {
|
||||||
|
parenDepth += 1;
|
||||||
|
} else if (ch === ')') {
|
||||||
|
parenDepth -= 1;
|
||||||
|
if (parenDepth === 0) {
|
||||||
|
signatureEnded = true;
|
||||||
|
}
|
||||||
|
} else if (ch === '{' && signatureEnded) {
|
||||||
|
braceStart = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (braceStart < 0) {
|
||||||
|
throw new Error(`missing body for function ${name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let depth = 0;
|
||||||
|
let end = braceStart;
|
||||||
|
for (; end < source.length; end += 1) {
|
||||||
|
const ch = source[end];
|
||||||
|
if (ch === '{') depth += 1;
|
||||||
|
if (ch === '}') {
|
||||||
|
depth -= 1;
|
||||||
|
if (depth === 0) {
|
||||||
|
end += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return source.slice(start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
const bundle = [
|
||||||
|
extractFunction('normalizeEmailGenerator'),
|
||||||
|
extractFunction('normalizeCustomEmailPool'),
|
||||||
|
extractFunction('getCustomEmailPool'),
|
||||||
|
extractFunction('getCustomEmailPoolEmailForRun'),
|
||||||
|
extractFunction('getEmailGeneratorLabel'),
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
function createApi() {
|
||||||
|
return new Function(`
|
||||||
|
const CUSTOM_EMAIL_POOL_GENERATOR = 'custom-pool';
|
||||||
|
const CLOUDFLARE_TEMP_EMAIL_GENERATOR = 'cloudflare-temp-email';
|
||||||
|
|
||||||
|
${bundle}
|
||||||
|
|
||||||
|
return {
|
||||||
|
normalizeEmailGenerator,
|
||||||
|
normalizeCustomEmailPool,
|
||||||
|
getCustomEmailPool,
|
||||||
|
getCustomEmailPoolEmailForRun,
|
||||||
|
getEmailGeneratorLabel,
|
||||||
|
};
|
||||||
|
`)();
|
||||||
|
}
|
||||||
|
|
||||||
|
test('background recognizes custom email pool generator and label', () => {
|
||||||
|
const api = createApi();
|
||||||
|
|
||||||
|
assert.equal(api.normalizeEmailGenerator('custom-pool'), 'custom-pool');
|
||||||
|
assert.equal(api.getEmailGeneratorLabel('custom-pool'), '自定义邮箱池');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('background normalizes custom email pool input and keeps order', () => {
|
||||||
|
const api = createApi();
|
||||||
|
|
||||||
|
assert.deepEqual(
|
||||||
|
api.normalizeCustomEmailPool(' Foo@Example.com \ninvalid\nbar@example.com;baz@example.com '),
|
||||||
|
['foo@example.com', 'bar@example.com', 'baz@example.com']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('background selects the matching email for the current auto-run round', () => {
|
||||||
|
const api = createApi();
|
||||||
|
const state = {
|
||||||
|
customEmailPool: ['first@example.com', 'second@example.com', 'third@example.com'],
|
||||||
|
};
|
||||||
|
|
||||||
|
assert.equal(api.getCustomEmailPoolEmailForRun(state, 1), 'first@example.com');
|
||||||
|
assert.equal(api.getCustomEmailPoolEmailForRun(state, 2), 'second@example.com');
|
||||||
|
assert.equal(api.getCustomEmailPoolEmailForRun(state, 4), '');
|
||||||
|
});
|
||||||
@@ -76,3 +76,63 @@ test('generated email helper falls back to normal generator when 2925 is in rece
|
|||||||
['email', 'duck@example.com'],
|
['email', 'duck@example.com'],
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('generated email helper can read the requested address from custom email pool', async () => {
|
||||||
|
const source = fs.readFileSync('background/generated-email-helpers.js', 'utf8');
|
||||||
|
const globalScope = {};
|
||||||
|
const api = new Function('self', `${source}; return self.MultiPageGeneratedEmailHelpers;`)(globalScope);
|
||||||
|
const events = [];
|
||||||
|
|
||||||
|
const helpers = api.createGeneratedEmailHelpers({
|
||||||
|
addLog: async () => {},
|
||||||
|
buildGeneratedAliasEmail: () => {
|
||||||
|
throw new Error('should not build alias');
|
||||||
|
},
|
||||||
|
buildCloudflareTempEmailHeaders: () => ({}),
|
||||||
|
CLOUDFLARE_TEMP_EMAIL_GENERATOR: 'cloudflare-temp-email',
|
||||||
|
CUSTOM_EMAIL_POOL_GENERATOR: 'custom-pool',
|
||||||
|
DUCK_AUTOFILL_URL: 'https://duckduckgo.com/email',
|
||||||
|
fetch: async () => ({ ok: true, text: async () => '{}' }),
|
||||||
|
fetchIcloudHideMyEmail: async () => {
|
||||||
|
throw new Error('should not use icloud generator');
|
||||||
|
},
|
||||||
|
getCloudflareTempEmailAddressFromResponse: () => '',
|
||||||
|
getCloudflareTempEmailConfig: () => ({ baseUrl: '', adminAuth: '', domain: '' }),
|
||||||
|
getCustomEmailPoolEmail: (state, targetRun) => state.customEmailPool?.[targetRun - 1] || '',
|
||||||
|
getState: async () => ({
|
||||||
|
customEmailPool: ['first@example.com', 'second@example.com'],
|
||||||
|
emailGenerator: 'custom-pool',
|
||||||
|
mailProvider: 'gmail',
|
||||||
|
}),
|
||||||
|
ensureMail2925AccountForFlow: async () => {
|
||||||
|
throw new Error('should not allocate 2925 account');
|
||||||
|
},
|
||||||
|
joinCloudflareTempEmailUrl: () => '',
|
||||||
|
normalizeCloudflareDomain: () => '',
|
||||||
|
normalizeCloudflareTempEmailAddress: () => '',
|
||||||
|
normalizeEmailGenerator: (value) => String(value || '').trim().toLowerCase(),
|
||||||
|
isGeneratedAliasProvider: () => false,
|
||||||
|
reuseOrCreateTab: async () => {},
|
||||||
|
sendToContentScript: async () => {
|
||||||
|
throw new Error('should not open duck tab');
|
||||||
|
},
|
||||||
|
setEmailState: async (email) => {
|
||||||
|
events.push(['email', email]);
|
||||||
|
},
|
||||||
|
throwIfStopped: () => {},
|
||||||
|
});
|
||||||
|
|
||||||
|
const email = await helpers.fetchGeneratedEmail({
|
||||||
|
customEmailPool: ['first@example.com', 'second@example.com'],
|
||||||
|
emailGenerator: 'custom-pool',
|
||||||
|
mailProvider: 'gmail',
|
||||||
|
}, {
|
||||||
|
generator: 'custom-pool',
|
||||||
|
poolIndex: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(email, 'second@example.com');
|
||||||
|
assert.deepStrictEqual(events, [
|
||||||
|
['email', 'second@example.com'],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|||||||
@@ -0,0 +1,115 @@
|
|||||||
|
const test = require('node:test');
|
||||||
|
const assert = require('node:assert/strict');
|
||||||
|
const fs = require('node:fs');
|
||||||
|
|
||||||
|
const source = fs.readFileSync('sidepanel/sidepanel.js', 'utf8');
|
||||||
|
|
||||||
|
function extractFunction(name) {
|
||||||
|
const markers = [`async function ${name}(`, `function ${name}(`];
|
||||||
|
const start = markers
|
||||||
|
.map((marker) => source.indexOf(marker))
|
||||||
|
.find((index) => index >= 0);
|
||||||
|
if (start < 0) {
|
||||||
|
throw new Error(`missing function ${name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let parenDepth = 0;
|
||||||
|
let signatureEnded = false;
|
||||||
|
let braceStart = -1;
|
||||||
|
for (let i = start; i < source.length; i += 1) {
|
||||||
|
const ch = source[i];
|
||||||
|
if (ch === '(') {
|
||||||
|
parenDepth += 1;
|
||||||
|
} else if (ch === ')') {
|
||||||
|
parenDepth -= 1;
|
||||||
|
if (parenDepth === 0) {
|
||||||
|
signatureEnded = true;
|
||||||
|
}
|
||||||
|
} else if (ch === '{' && signatureEnded) {
|
||||||
|
braceStart = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (braceStart < 0) {
|
||||||
|
throw new Error(`missing body for function ${name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let depth = 0;
|
||||||
|
let end = braceStart;
|
||||||
|
for (; end < source.length; end += 1) {
|
||||||
|
const ch = source[end];
|
||||||
|
if (ch === '{') depth += 1;
|
||||||
|
if (ch === '}') {
|
||||||
|
depth -= 1;
|
||||||
|
if (depth === 0) {
|
||||||
|
end += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return source.slice(start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
test('sidepanel html exposes custom email pool generator option and input row', () => {
|
||||||
|
const html = fs.readFileSync('sidepanel/sidepanel.html', 'utf8');
|
||||||
|
|
||||||
|
assert.match(html, /option value="custom-pool">自定义邮箱池<\/option>/);
|
||||||
|
assert.match(html, /id="row-custom-email-pool"/);
|
||||||
|
assert.match(html, /id="input-custom-email-pool"/);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('sidepanel locks run count to custom email pool size', () => {
|
||||||
|
const bundle = [
|
||||||
|
extractFunction('isCustomMailProvider'),
|
||||||
|
extractFunction('normalizeCustomEmailPoolEntries'),
|
||||||
|
extractFunction('getSelectedEmailGenerator'),
|
||||||
|
extractFunction('usesGeneratedAliasMailProvider'),
|
||||||
|
extractFunction('usesCustomEmailPoolGenerator'),
|
||||||
|
extractFunction('getCustomEmailPoolSize'),
|
||||||
|
extractFunction('getRunCountValue'),
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
const api = new Function(`
|
||||||
|
const GMAIL_PROVIDER = 'gmail';
|
||||||
|
const GMAIL_ALIAS_GENERATOR = 'gmail-alias';
|
||||||
|
const CUSTOM_EMAIL_POOL_GENERATOR = 'custom-pool';
|
||||||
|
const selectMailProvider = { value: 'gmail' };
|
||||||
|
const selectEmailGenerator = { value: 'custom-pool' };
|
||||||
|
const inputCustomEmailPool = { value: 'first@example.com\\nsecond@example.com' };
|
||||||
|
const inputRunCount = { value: '99' };
|
||||||
|
|
||||||
|
function isLuckmailProvider() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isManagedAliasProvider() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSelectedMail2925Mode() {
|
||||||
|
return 'provide';
|
||||||
|
}
|
||||||
|
|
||||||
|
function isManagedAliasProvider(provider) {
|
||||||
|
return String(provider || '').trim().toLowerCase() === GMAIL_PROVIDER;
|
||||||
|
}
|
||||||
|
|
||||||
|
${bundle}
|
||||||
|
|
||||||
|
return {
|
||||||
|
getSelectedEmailGenerator,
|
||||||
|
usesGeneratedAliasMailProvider,
|
||||||
|
usesCustomEmailPoolGenerator,
|
||||||
|
getCustomEmailPoolSize,
|
||||||
|
getRunCountValue,
|
||||||
|
};
|
||||||
|
`)();
|
||||||
|
|
||||||
|
assert.equal(api.getSelectedEmailGenerator(), 'custom-pool');
|
||||||
|
assert.equal(api.usesGeneratedAliasMailProvider('gmail', 'provide', 'gmail-alias'), true);
|
||||||
|
assert.equal(api.usesGeneratedAliasMailProvider('gmail', 'provide', 'custom-pool'), false);
|
||||||
|
assert.equal(api.usesCustomEmailPoolGenerator(), true);
|
||||||
|
assert.equal(api.getCustomEmailPoolSize(), 2);
|
||||||
|
assert.equal(api.getRunCountValue(), 2);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user