feat: add Inbucket mailbox support and enhance password management in side panel

This commit is contained in:
Jimmy
2026-04-06 12:01:20 +08:00
parent 2be94e6765
commit 8b0ffa330f
9 changed files with 420 additions and 17 deletions
+5
View File
@@ -301,6 +301,11 @@ header {
padding-inline: 10px;
}
#btn-toggle-password {
min-width: 58px;
padding-inline: 10px;
}
.data-select {
flex: 1;
padding: 7px 10px;
+12
View File
@@ -53,8 +53,13 @@
<select id="select-mail-provider" class="data-select">
<option value="163">163 Mail (mail.163.com)</option>
<option value="qq">QQ Mail (wx.mail.qq.com)</option>
<option value="inbucket">Inbucket (inbucket.j2to.de/m/&lt;mailbox&gt;/)</option>
</select>
</div>
<div class="data-row" id="row-inbucket-mailbox" style="display:none;">
<span class="data-label">Mailbox</span>
<input type="text" id="input-inbucket-mailbox" class="data-input" placeholder="e.g. zju2001" />
</div>
<div class="data-row">
<span class="data-label">Email</span>
<div class="data-inline">
@@ -62,6 +67,13 @@
<button id="btn-fetch-email" class="btn btn-outline btn-sm" type="button">Auto</button>
</div>
</div>
<div class="data-row">
<span class="data-label">Password</span>
<div class="data-inline">
<input type="password" id="input-password" class="data-input" placeholder="Leave blank to auto-generate" />
<button id="btn-toggle-password" class="btn btn-outline btn-sm" type="button">Show</button>
</div>
</div>
<div class="data-row">
<span class="data-label">OAuth</span>
<span id="display-oauth-url" class="data-value mono truncate">Waiting...</span>
+49
View File
@@ -14,7 +14,9 @@ const displayLocalhostUrl = document.getElementById('display-localhost-url');
const displayStatus = document.getElementById('display-status');
const statusBar = document.getElementById('status-bar');
const inputEmail = document.getElementById('input-email');
const inputPassword = document.getElementById('input-password');
const btnFetchEmail = document.getElementById('btn-fetch-email');
const btnTogglePassword = document.getElementById('btn-toggle-password');
const btnStop = document.getElementById('btn-stop');
const btnReset = document.getElementById('btn-reset');
const stepsProgress = document.getElementById('steps-progress');
@@ -24,6 +26,8 @@ const autoContinueBar = document.getElementById('auto-continue-bar');
const btnClearLog = document.getElementById('btn-clear-log');
const inputVpsUrl = document.getElementById('input-vps-url');
const selectMailProvider = document.getElementById('select-mail-provider');
const rowInbucketMailbox = document.getElementById('row-inbucket-mailbox');
const inputInbucketMailbox = document.getElementById('input-inbucket-mailbox');
const inputRunCount = document.getElementById('input-run-count');
// ============================================================
@@ -77,12 +81,16 @@ async function restoreState() {
if (state.email) {
inputEmail.value = state.email;
}
syncPasswordField(state);
if (state.vpsUrl) {
inputVpsUrl.value = state.vpsUrl;
}
if (state.mailProvider) {
selectMailProvider.value = state.mailProvider;
}
if (state.inbucketMailbox) {
inputInbucketMailbox.value = state.inbucketMailbox;
}
if (state.stepStatuses) {
for (const [step, status] of Object.entries(state.stepStatuses)) {
@@ -98,11 +106,21 @@ async function restoreState() {
updateStatusDisplay(state);
updateProgressCounter();
updateMailProviderUI();
} catch (err) {
console.error('Failed to restore state:', err);
}
}
function syncPasswordField(state) {
inputPassword.value = state.customPassword || state.password || '';
}
function updateMailProviderUI() {
const useInbucket = selectMailProvider.value === 'inbucket';
rowInbucketMailbox.style.display = useInbucket ? '' : 'none';
}
// ============================================================
// UI Updates
// ============================================================
@@ -262,6 +280,10 @@ async function fetchDuckEmail() {
}
}
function syncPasswordToggleLabel() {
btnTogglePassword.textContent = inputPassword.type === 'password' ? 'Show' : 'Hide';
}
// ============================================================
// Button Handlers
// ============================================================
@@ -286,6 +308,11 @@ btnFetchEmail.addEventListener('click', async () => {
await fetchDuckEmail().catch(() => {});
});
btnTogglePassword.addEventListener('click', () => {
inputPassword.type = inputPassword.type === 'password' ? 'text' : 'password';
syncPasswordToggleLabel();
});
btnStop.addEventListener('click', async () => {
btnStop.disabled = true;
await chrome.runtime.sendMessage({ type: 'STOP_FLOW', source: 'sidepanel', payload: {} });
@@ -355,13 +382,30 @@ inputVpsUrl.addEventListener('change', async () => {
}
});
inputPassword.addEventListener('change', async () => {
await chrome.runtime.sendMessage({
type: 'SAVE_SETTING',
source: 'sidepanel',
payload: { customPassword: inputPassword.value },
});
});
selectMailProvider.addEventListener('change', async () => {
updateMailProviderUI();
await chrome.runtime.sendMessage({
type: 'SAVE_SETTING', source: 'sidepanel',
payload: { mailProvider: selectMailProvider.value },
});
});
inputInbucketMailbox.addEventListener('change', async () => {
await chrome.runtime.sendMessage({
type: 'SAVE_SETTING',
source: 'sidepanel',
payload: { inbucketMailbox: inputInbucketMailbox.value.trim() },
});
});
// ============================================================
// Listen for Background broadcasts
// ============================================================
@@ -381,6 +425,7 @@ chrome.runtime.onMessage.addListener((message) => {
chrome.runtime.sendMessage({ type: 'GET_STATE', source: 'sidepanel' }).then(updateStatusDisplay);
if (status === 'completed') {
chrome.runtime.sendMessage({ type: 'GET_STATE', source: 'sidepanel' }).then(state => {
syncPasswordField(state);
if (state.oauthUrl) {
displayOauthUrl.textContent = state.oauthUrl;
displayOauthUrl.classList.add('has-value');
@@ -415,6 +460,9 @@ chrome.runtime.onMessage.addListener((message) => {
if (message.payload.email) {
inputEmail.value = message.payload.email;
}
if (message.payload.password !== undefined) {
inputPassword.value = message.payload.password || '';
}
if (message.payload.oauthUrl) {
displayOauthUrl.textContent = message.payload.oauthUrl;
displayOauthUrl.classList.add('has-value');
@@ -490,5 +538,6 @@ btnTheme.addEventListener('click', () => {
initTheme();
restoreState().then(() => {
syncPasswordToggleLabel();
updateButtonStates();
});