添加Cloudflare服务
This commit is contained in:
+217
-10
@@ -36,10 +36,15 @@ const btnClearLog = document.getElementById('btn-clear-log');
|
||||
const inputVpsUrl = document.getElementById('input-vps-url');
|
||||
const inputVpsPassword = document.getElementById('input-vps-password');
|
||||
const selectMailProvider = document.getElementById('select-mail-provider');
|
||||
const selectEmailGenerator = document.getElementById('select-email-generator');
|
||||
const rowInbucketHost = document.getElementById('row-inbucket-host');
|
||||
const inputInbucketHost = document.getElementById('input-inbucket-host');
|
||||
const rowInbucketMailbox = document.getElementById('row-inbucket-mailbox');
|
||||
const inputInbucketMailbox = document.getElementById('input-inbucket-mailbox');
|
||||
const rowCfDomain = document.getElementById('row-cf-domain');
|
||||
const selectCfDomain = document.getElementById('select-cf-domain');
|
||||
const inputCfDomain = document.getElementById('input-cf-domain');
|
||||
const btnCfDomainMode = document.getElementById('btn-cf-domain-mode');
|
||||
const inputRunCount = document.getElementById('input-run-count');
|
||||
const inputAutoSkipFailures = document.getElementById('input-auto-skip-failures');
|
||||
const inputAutoDelayEnabled = document.getElementById('input-auto-delay-enabled');
|
||||
@@ -79,6 +84,7 @@ let currentAutoRun = {
|
||||
let settingsDirty = false;
|
||||
let settingsSaveInFlight = false;
|
||||
let settingsAutoSaveTimer = null;
|
||||
let cloudflareDomainEditMode = false;
|
||||
let modalChoiceResolver = null;
|
||||
let currentModalActions = [];
|
||||
let scheduledCountdownTimer = null;
|
||||
@@ -367,14 +373,96 @@ function setDefaultAutoRunButton() {
|
||||
btnAutoRun.innerHTML = '<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><polygon points="5 3 19 12 5 21 5 3"/></svg> 自动';
|
||||
}
|
||||
|
||||
function normalizeCloudflareDomainValue(value = '') {
|
||||
let normalized = String(value || '').trim().toLowerCase();
|
||||
if (!normalized) return '';
|
||||
normalized = normalized.replace(/^@+/, '');
|
||||
normalized = normalized.replace(/^https?:\/\//, '');
|
||||
normalized = normalized.replace(/\/.*$/, '');
|
||||
if (!/^[a-z0-9.-]+\.[a-z]{2,}$/.test(normalized)) {
|
||||
return '';
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
function normalizeCloudflareDomains(values = []) {
|
||||
const seen = new Set();
|
||||
const domains = [];
|
||||
for (const value of Array.isArray(values) ? values : []) {
|
||||
const normalized = normalizeCloudflareDomainValue(value);
|
||||
if (!normalized || seen.has(normalized)) continue;
|
||||
seen.add(normalized);
|
||||
domains.push(normalized);
|
||||
}
|
||||
return domains;
|
||||
}
|
||||
|
||||
function getCloudflareDomainsFromState() {
|
||||
const domains = normalizeCloudflareDomains(latestState?.cloudflareDomains || []);
|
||||
const activeDomain = normalizeCloudflareDomainValue(latestState?.cloudflareDomain || '');
|
||||
if (activeDomain && !domains.includes(activeDomain)) {
|
||||
domains.unshift(activeDomain);
|
||||
}
|
||||
return { domains, activeDomain: activeDomain || domains[0] || '' };
|
||||
}
|
||||
|
||||
function renderCloudflareDomainOptions(preferredDomain = '') {
|
||||
const preferred = normalizeCloudflareDomainValue(preferredDomain);
|
||||
const { domains, activeDomain } = getCloudflareDomainsFromState();
|
||||
const selected = preferred || activeDomain;
|
||||
|
||||
selectCfDomain.innerHTML = '';
|
||||
if (domains.length === 0) {
|
||||
const option = document.createElement('option');
|
||||
option.value = '';
|
||||
option.textContent = '请先添加域名';
|
||||
selectCfDomain.appendChild(option);
|
||||
selectCfDomain.disabled = true;
|
||||
selectCfDomain.value = '';
|
||||
return;
|
||||
}
|
||||
|
||||
for (const domain of domains) {
|
||||
const option = document.createElement('option');
|
||||
option.value = domain;
|
||||
option.textContent = domain;
|
||||
selectCfDomain.appendChild(option);
|
||||
}
|
||||
selectCfDomain.disabled = false;
|
||||
selectCfDomain.value = domains.includes(selected) ? selected : domains[0];
|
||||
}
|
||||
|
||||
function setCloudflareDomainEditMode(editing, options = {}) {
|
||||
const { clearInput = false } = options;
|
||||
cloudflareDomainEditMode = Boolean(editing);
|
||||
selectCfDomain.style.display = cloudflareDomainEditMode ? 'none' : '';
|
||||
inputCfDomain.style.display = cloudflareDomainEditMode ? '' : 'none';
|
||||
btnCfDomainMode.textContent = cloudflareDomainEditMode ? '保存' : '添加';
|
||||
if (cloudflareDomainEditMode) {
|
||||
if (clearInput) {
|
||||
inputCfDomain.value = '';
|
||||
}
|
||||
inputCfDomain.focus();
|
||||
} else if (clearInput) {
|
||||
inputCfDomain.value = '';
|
||||
}
|
||||
}
|
||||
|
||||
function collectSettingsPayload() {
|
||||
const { domains, activeDomain } = getCloudflareDomainsFromState();
|
||||
const selectedCloudflareDomain = normalizeCloudflareDomainValue(
|
||||
!cloudflareDomainEditMode ? selectCfDomain.value : activeDomain
|
||||
) || activeDomain;
|
||||
return {
|
||||
vpsUrl: inputVpsUrl.value.trim(),
|
||||
vpsPassword: inputVpsPassword.value,
|
||||
customPassword: inputPassword.value,
|
||||
mailProvider: selectMailProvider.value,
|
||||
emailGenerator: selectEmailGenerator.value,
|
||||
inbucketHost: inputInbucketHost.value.trim(),
|
||||
inbucketMailbox: inputInbucketMailbox.value.trim(),
|
||||
cloudflareDomain: selectedCloudflareDomain,
|
||||
cloudflareDomains: domains,
|
||||
autoRunSkipFailures: inputAutoSkipFailures.checked,
|
||||
autoRunDelayEnabled: inputAutoDelayEnabled.checked,
|
||||
autoRunDelayMinutes: normalizeAutoDelayMinutes(inputAutoDelayMinutes.value),
|
||||
@@ -551,12 +639,17 @@ async function restoreState() {
|
||||
if (state.mailProvider) {
|
||||
selectMailProvider.value = state.mailProvider;
|
||||
}
|
||||
if (state.emailGenerator) {
|
||||
selectEmailGenerator.value = state.emailGenerator;
|
||||
}
|
||||
if (state.inbucketHost) {
|
||||
inputInbucketHost.value = state.inbucketHost;
|
||||
}
|
||||
if (state.inbucketMailbox) {
|
||||
inputInbucketMailbox.value = state.inbucketMailbox;
|
||||
}
|
||||
renderCloudflareDomainOptions(state.cloudflareDomain || '');
|
||||
setCloudflareDomainEditMode(false, { clearInput: true });
|
||||
inputAutoSkipFailures.checked = Boolean(state.autoRunSkipFailures);
|
||||
inputAutoDelayEnabled.checked = Boolean(state.autoRunDelayEnabled);
|
||||
inputAutoDelayMinutes.value = String(normalizeAutoDelayMinutes(state.autoRunDelayMinutes));
|
||||
@@ -592,10 +685,78 @@ function syncPasswordField(state) {
|
||||
inputPassword.value = state.customPassword || state.password || '';
|
||||
}
|
||||
|
||||
function getSelectedEmailGenerator() {
|
||||
return selectEmailGenerator.value === 'cloudflare' ? 'cloudflare' : 'duck';
|
||||
}
|
||||
|
||||
function getEmailGeneratorUiCopy() {
|
||||
if (getSelectedEmailGenerator() === 'cloudflare') {
|
||||
return {
|
||||
buttonLabel: '生成 Cloudflare',
|
||||
placeholder: '点击生成 Cloudflare 邮箱,或手动粘贴邮箱',
|
||||
successVerb: '生成',
|
||||
label: 'Cloudflare 邮箱',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
buttonLabel: '获取 Duck',
|
||||
placeholder: '点击获取 DuckDuckGo 邮箱,或手动粘贴邮箱',
|
||||
successVerb: '获取',
|
||||
label: 'Duck 邮箱',
|
||||
};
|
||||
}
|
||||
|
||||
function updateMailProviderUI() {
|
||||
const useInbucket = selectMailProvider.value === 'inbucket';
|
||||
rowInbucketHost.style.display = useInbucket ? '' : 'none';
|
||||
rowInbucketMailbox.style.display = useInbucket ? '' : 'none';
|
||||
const useCloudflare = selectEmailGenerator.value === 'cloudflare';
|
||||
rowCfDomain.style.display = useCloudflare ? '' : 'none';
|
||||
const { domains } = getCloudflareDomainsFromState();
|
||||
if (useCloudflare) {
|
||||
setCloudflareDomainEditMode(cloudflareDomainEditMode || domains.length === 0, { clearInput: false });
|
||||
} else {
|
||||
setCloudflareDomainEditMode(false, { clearInput: false });
|
||||
}
|
||||
|
||||
const uiCopy = getEmailGeneratorUiCopy();
|
||||
inputEmail.placeholder = uiCopy.placeholder;
|
||||
if (!btnFetchEmail.disabled) {
|
||||
btnFetchEmail.textContent = uiCopy.buttonLabel;
|
||||
}
|
||||
}
|
||||
|
||||
async function saveCloudflareDomainSettings(domains, activeDomain, options = {}) {
|
||||
const { silent = false } = options;
|
||||
const normalizedDomains = normalizeCloudflareDomains(domains);
|
||||
const normalizedActiveDomain = normalizeCloudflareDomainValue(activeDomain) || normalizedDomains[0] || '';
|
||||
const payload = {
|
||||
cloudflareDomain: normalizedActiveDomain,
|
||||
cloudflareDomains: normalizedDomains,
|
||||
};
|
||||
|
||||
const response = await chrome.runtime.sendMessage({
|
||||
type: 'SAVE_SETTING',
|
||||
source: 'sidepanel',
|
||||
payload,
|
||||
});
|
||||
|
||||
if (response?.error) {
|
||||
throw new Error(response.error);
|
||||
}
|
||||
|
||||
syncLatestState({
|
||||
...payload,
|
||||
});
|
||||
renderCloudflareDomainOptions(normalizedActiveDomain);
|
||||
setCloudflareDomainEditMode(false, { clearInput: true });
|
||||
markSettingsDirty(false);
|
||||
updateMailProviderUI();
|
||||
|
||||
if (!silent) {
|
||||
showToast('Cloudflare 域名已保存', 'success', 1800);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
@@ -773,32 +934,36 @@ function escapeHtml(text) {
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
async function fetchDuckEmail(options = {}) {
|
||||
async function fetchGeneratedEmail(options = {}) {
|
||||
const { showFailureToast = true } = options;
|
||||
const defaultLabel = '获取';
|
||||
const uiCopy = getEmailGeneratorUiCopy();
|
||||
const defaultLabel = uiCopy.buttonLabel;
|
||||
btnFetchEmail.disabled = true;
|
||||
btnFetchEmail.textContent = '...';
|
||||
|
||||
try {
|
||||
const response = await chrome.runtime.sendMessage({
|
||||
type: 'FETCH_DUCK_EMAIL',
|
||||
type: 'FETCH_GENERATED_EMAIL',
|
||||
source: 'sidepanel',
|
||||
payload: { generateNew: true },
|
||||
payload: {
|
||||
generateNew: true,
|
||||
generator: selectEmailGenerator.value,
|
||||
},
|
||||
});
|
||||
|
||||
if (response?.error) {
|
||||
throw new Error(response.error);
|
||||
}
|
||||
if (!response?.email) {
|
||||
throw new Error('未返回 Duck 邮箱。');
|
||||
throw new Error('未返回可用邮箱。');
|
||||
}
|
||||
|
||||
inputEmail.value = response.email;
|
||||
showToast(`已获取 ${response.email}`, 'success', 2500);
|
||||
showToast(`已${uiCopy.successVerb} ${uiCopy.label}:${response.email}`, 'success', 2500);
|
||||
return response.email;
|
||||
} catch (err) {
|
||||
if (showFailureToast) {
|
||||
showToast(`自动获取失败:${err.message}`, 'error');
|
||||
showToast(`${uiCopy.label}${uiCopy.successVerb}失败:${err.message}`, 'error');
|
||||
}
|
||||
throw err;
|
||||
} finally {
|
||||
@@ -897,7 +1062,7 @@ document.querySelectorAll('.step-btn').forEach(btn => {
|
||||
let email = inputEmail.value.trim();
|
||||
if (!email) {
|
||||
try {
|
||||
email = await fetchDuckEmail({ showFailureToast: false });
|
||||
email = await fetchGeneratedEmail({ showFailureToast: false });
|
||||
} catch (err) {
|
||||
showToast(`自动获取失败:${err.message},请手动粘贴邮箱后重试。`, 'warn');
|
||||
return;
|
||||
@@ -920,7 +1085,7 @@ document.querySelectorAll('.step-btn').forEach(btn => {
|
||||
});
|
||||
|
||||
btnFetchEmail.addEventListener('click', async () => {
|
||||
await fetchDuckEmail().catch(() => { });
|
||||
await fetchGeneratedEmail().catch(() => { });
|
||||
});
|
||||
|
||||
btnTogglePassword.addEventListener('click', () => {
|
||||
@@ -1000,7 +1165,7 @@ btnAutoRun.addEventListener('click', async () => {
|
||||
btnAutoContinue.addEventListener('click', async () => {
|
||||
const email = inputEmail.value.trim();
|
||||
if (!email) {
|
||||
showToast('请先获取或粘贴 DuckDuckGo 邮箱。', 'warn');
|
||||
showToast('请先获取或粘贴邮箱。', 'warn');
|
||||
return;
|
||||
}
|
||||
autoContinueBar.style.display = 'none';
|
||||
@@ -1107,6 +1272,48 @@ selectMailProvider.addEventListener('change', () => {
|
||||
saveSettings({ silent: true }).catch(() => { });
|
||||
});
|
||||
|
||||
selectEmailGenerator.addEventListener('change', () => {
|
||||
updateMailProviderUI();
|
||||
markSettingsDirty(true);
|
||||
saveSettings({ silent: true }).catch(() => { });
|
||||
});
|
||||
|
||||
selectCfDomain.addEventListener('change', () => {
|
||||
if (selectCfDomain.disabled) {
|
||||
return;
|
||||
}
|
||||
markSettingsDirty(true);
|
||||
saveSettings({ silent: true }).catch(() => { });
|
||||
});
|
||||
|
||||
btnCfDomainMode.addEventListener('click', async () => {
|
||||
try {
|
||||
if (!cloudflareDomainEditMode) {
|
||||
setCloudflareDomainEditMode(true, { clearInput: true });
|
||||
return;
|
||||
}
|
||||
|
||||
const newDomain = normalizeCloudflareDomainValue(inputCfDomain.value);
|
||||
if (!newDomain) {
|
||||
showToast('请输入有效的 Cloudflare 域名。', 'warn');
|
||||
inputCfDomain.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
const { domains } = getCloudflareDomainsFromState();
|
||||
await saveCloudflareDomainSettings([...domains, newDomain], newDomain);
|
||||
} catch (err) {
|
||||
showToast(err.message, 'error');
|
||||
}
|
||||
});
|
||||
|
||||
inputCfDomain.addEventListener('keydown', (event) => {
|
||||
if (event.key === 'Enter') {
|
||||
event.preventDefault();
|
||||
btnCfDomainMode.click();
|
||||
}
|
||||
});
|
||||
|
||||
inputInbucketMailbox.addEventListener('input', () => {
|
||||
markSettingsDirty(true);
|
||||
scheduleSettingsAutoSave();
|
||||
|
||||
Reference in New Issue
Block a user