unlock.ts raw
1 import browser from 'webextension-polyfill';
2
3 export interface UnlockRequestMessage {
4 type: 'unlock-request';
5 id: string;
6 password: string;
7 }
8
9 export interface UnlockResponseMessage {
10 type: 'unlock-response';
11 id: string;
12 success: boolean;
13 error?: string;
14 }
15
16 const params = new URLSearchParams(location.search);
17 const id = params.get('id') as string;
18 const host = params.get('host');
19
20 // Elements
21 const passwordInput = document.getElementById('passwordInput') as HTMLInputElement;
22 const togglePasswordBtn = document.getElementById('togglePassword');
23 const unlockBtn = document.getElementById('unlockBtn') as HTMLButtonElement;
24 const derivingOverlay = document.getElementById('derivingOverlay');
25 const errorAlert = document.getElementById('errorAlert');
26 const errorMessage = document.getElementById('errorMessage');
27 const hostInfo = document.getElementById('hostInfo');
28 const hostSpan = document.getElementById('hostSpan');
29
30 // Show host info if available
31 if (host && hostInfo && hostSpan) {
32 hostSpan.innerText = host;
33 hostInfo.classList.remove('hidden');
34 }
35
36 // Toggle password visibility
37 togglePasswordBtn?.addEventListener('click', () => {
38 if (passwordInput.type === 'password') {
39 passwordInput.type = 'text';
40 togglePasswordBtn.innerHTML = '<i class="bi bi-eye-slash"></i>';
41 } else {
42 passwordInput.type = 'password';
43 togglePasswordBtn.innerHTML = '<i class="bi bi-eye"></i>';
44 }
45 });
46
47 // Enable/disable unlock button based on password input
48 passwordInput?.addEventListener('input', () => {
49 unlockBtn.disabled = !passwordInput.value;
50 });
51
52 // Handle enter key
53 passwordInput?.addEventListener('keyup', (e) => {
54 if (e.key === 'Enter' && passwordInput.value) {
55 attemptUnlock();
56 }
57 });
58
59 // Handle unlock button click
60 unlockBtn?.addEventListener('click', attemptUnlock);
61
62 async function attemptUnlock() {
63 if (!passwordInput?.value) return;
64
65 // Show deriving overlay
66 derivingOverlay?.classList.remove('hidden');
67 errorAlert?.classList.add('hidden');
68
69 const message: UnlockRequestMessage = {
70 type: 'unlock-request',
71 id,
72 password: passwordInput.value,
73 };
74
75 try {
76 const response = await browser.runtime.sendMessage(message) as UnlockResponseMessage;
77
78 if (response.success) {
79 // Success - close the window
80 window.close();
81 } else {
82 // Failed - show error
83 derivingOverlay?.classList.add('hidden');
84 showError(response.error || 'Invalid password');
85 }
86 } catch (error) {
87 console.error('Failed to send unlock message:', error);
88 derivingOverlay?.classList.add('hidden');
89 showError('Failed to unlock vault');
90 }
91 }
92
93 function showError(message: string) {
94 if (errorAlert && errorMessage) {
95 errorMessage.innerText = message;
96 errorAlert.classList.remove('hidden');
97 setTimeout(() => {
98 errorAlert.classList.add('hidden');
99 }, 3000);
100 }
101 }
102
103 // Focus password input on load
104 document.addEventListener('DOMContentLoaded', () => {
105 passwordInput?.focus();
106 });
107