import {
isAcceptableNewAccessPin,
isForbiddenAccessPin,
isValidAccessPin,
normalizePinDigits
} from '../lib/ellyAccessPin.js';
document.addEventListener('DOMContentLoaded', () => {
let enteredPIN = '';
let confirmPIN = '';
let setupStep = 'enter'; // enter | confirm (setup mode only)
const pinDisplay = document.getElementById('pinDisplay');
const errorMessage = document.getElementById('errorMessage');
const titleEl = document.querySelector('h1');
const subtitleEl = document.querySelector('.subtitle');
const params = new URLSearchParams(window.location.search);
const isSetupMode = params.get('mode') === 'setup';
if (isSetupMode) {
if (titleEl) {
titleEl.textContent = 'Set Access PIN';
}
if (subtitleEl) {
subtitleEl.textContent = 'Choose an 8-digit Access PIN (not 12345678)';
}
}
// Initialize PIN display
updatePinDisplay();
// Number buttons
document.querySelectorAll('.pin-btn[data-digit]').forEach(btn => {
btn.addEventListener('click', (e) => {
const target = /** @type {HTMLElement} */ (e.currentTarget);
const digit = target?.dataset?.digit;
if (!digit) {
return;
}
if (enteredPIN.length < 8) {
enteredPIN += digit;
updatePinDisplay();
if (errorMessage) {
errorMessage.textContent = '';
}
}
});
});
// Backspace button
document.getElementById('btnBackspace')?.addEventListener('click', () => {
if (enteredPIN.length > 0) {
enteredPIN = enteredPIN.slice(0, -1);
updatePinDisplay();
if (errorMessage) {
errorMessage.textContent = '';
}
}
});
// Clear button
document.getElementById('btnClear')?.addEventListener('click', () => {
enteredPIN = '';
updatePinDisplay();
if (errorMessage) {
errorMessage.textContent = '';
}
});
// Submit button
document.getElementById('btnSubmit')?.addEventListener('click', () => {
submitPin().catch((err) => console.error(err));
});
// Enter key support
document.addEventListener('keydown', (e) => {
if (e.key >= '0' && e.key <= '9' && enteredPIN.length < 8) {
enteredPIN += e.key;
updatePinDisplay();
if (errorMessage) {
errorMessage.textContent = '';
}
} else if (e.key === 'Backspace') {
enteredPIN = enteredPIN.slice(0, -1);
updatePinDisplay();
if (errorMessage) {
errorMessage.textContent = '';
}
} else if (e.key === 'Enter') {
submitPin().catch((err) => console.error(err));
}
});
/**
* Renders the 8 PIN digit slots.
* @returns {void}
*/
function updatePinDisplay() {
if (!pinDisplay) {
return;
}
pinDisplay.innerHTML = '';
for (let i = 0; i < 8; i++) {
const digitDiv = document.createElement('div');
digitDiv.className = 'pin-digit';
digitDiv.textContent = enteredPIN[i] || '•';
pinDisplay.appendChild(digitDiv);
}
}
/**
* Opens the main popup window after successful Access PIN auth.
* @returns {Promise<void>}
*/
async function openMainPopupThenClose() {
try {
await chrome.windows.create({
url: chrome.runtime.getURL('popup/popup.html'),
type: 'popup',
width: 560,
height: 640,
focused: true
});
} catch (err) {
console.error('Elly pin: open popup failed', err);
}
window.close();
}
/**
* Handles submit for unlock or setup (two-step confirm).
* @returns {Promise<void>}
*/
async function submitPin() {
if (!errorMessage) {
return;
}
if (enteredPIN.length !== 8) {
errorMessage.textContent = 'Please enter 8 digits';
return;
}
const pin = normalizePinDigits(enteredPIN);
if (isSetupMode) {
if (setupStep === 'enter') {
if (!isAcceptableNewAccessPin(pin)) {
errorMessage.textContent = isForbiddenAccessPin(pin)
? 'That PIN is not allowed. Choose a different 8-digit PIN.'
: 'PIN must be 8 digits';
enteredPIN = '';
updatePinDisplay();
return;
}
confirmPIN = pin;
enteredPIN = '';
setupStep = 'confirm';
if (subtitleEl) {
subtitleEl.textContent = 'Confirm your 8-digit Access PIN';
}
updatePinDisplay();
return;
}
if (pin !== confirmPIN) {
errorMessage.textContent = 'PINs do not match. Try again.';
enteredPIN = '';
confirmPIN = '';
setupStep = 'enter';
if (subtitleEl) {
subtitleEl.textContent = 'Choose an 8-digit Access PIN (not 12345678)';
}
updatePinDisplay();
return;
}
try {
const response = await chrome.runtime.sendMessage({
action: 'setNewPIN',
newPin: pin
});
if (!response?.success) {
errorMessage.textContent = response?.error || 'Could not save Access PIN';
enteredPIN = '';
updatePinDisplay();
return;
}
await openMainPopupThenClose();
} catch (error) {
errorMessage.textContent = 'Error saving PIN. Please try again.';
console.error('PIN setup error:', error);
}
return;
}
// Unlock mode — always verify via background (never client-only compare)
if (!isValidAccessPin(pin) || isForbiddenAccessPin(pin)) {
errorMessage.textContent = 'Invalid Access PIN';
enteredPIN = '';
updatePinDisplay();
return;
}
try {
const response = await chrome.runtime.sendMessage({
action: 'verifyAccessPin',
pin
});
if (response?.success) {
await openMainPopupThenClose();
} else {
errorMessage.textContent = response?.error || 'Incorrect PIN. Please try again.';
enteredPIN = '';
updatePinDisplay();
errorMessage.style.animation = 'none';
setTimeout(() => {
errorMessage.style.animation = 'shake 0.5s';
}, 10);
}
} catch (error) {
errorMessage.textContent = 'Error verifying PIN. Please try again.';
console.error('PIN verification error:', error);
}
}
});