v1.0.1-beta: replace nodeIntegration/contextIsolation:false with contextBridge preload

All 6 popup BrowserWindows (lockout, prompt, pause, pin, keyboard ×2)
now use contextIsolation:true + popup-preload.js instead of the
deprecated nodeIntegration:true pattern. A new popup-preload.js file
exposes crypto.hashPassword, fs.readPin, ipcRenderer.send/on/once to
the renderer via contextBridge. All affected HTML files updated to use
window.electronAPI.* instead of direct require('electron') calls.
The popup-preload.js heredoc is also added to the upgrade extract_file
list so upgrades re-extract it correctly.

https://claude.ai/code/session_01M3tiofbGfmTddeMcXr8nXr
This commit is contained in:
Claude
2026-04-21 01:29:27 +00:00
parent 589a65bc55
commit a7894ede51
+47 -41
View File
@@ -4204,8 +4204,8 @@ function showLockoutScreen(){
frame:false, frame:false,
backgroundColor:'#000000', backgroundColor:'#000000',
webPreferences:{ webPreferences:{
nodeIntegration:true, contextIsolation:true,
contextIsolation:false preload:path.join(__dirname,'popup-preload.js')
} }
}); });
@@ -4262,20 +4262,17 @@ function showLockoutScreen(){
<div class="error" id="error">Incorrect password</div> <div class="error" id="error">Incorrect password</div>
</div> </div>
<script> <script>
const crypto=require('crypto');
const{ipcRenderer}=require('electron');
function checkPassword(){ function checkPassword(){
const pass=document.getElementById('password').value; const pass=document.getElementById('password').value;
const hash=crypto.createHash('sha256').update(pass).digest('hex'); const hash=window.electronAPI.hashPassword(pass);
ipcRenderer.send('check-lockout-password',hash); window.electronAPI.send('check-lockout-password',hash);
} }
document.getElementById('password').addEventListener('keydown',(e)=>{ document.getElementById('password').addEventListener('keydown',(e)=>{
if(e.key==='Enter')checkPassword(); if(e.key==='Enter')checkPassword();
}); });
ipcRenderer.on('password-incorrect',()=>{ window.electronAPI.on('password-incorrect',()=>{
document.getElementById('error').style.display='block'; document.getElementById('error').style.display='block';
document.getElementById('password').value=''; document.getElementById('password').value='';
document.getElementById('password').focus(); document.getElementById('password').focus();
@@ -4886,7 +4883,7 @@ function showInactivityPrompt(){
alwaysOnTop:true, alwaysOnTop:true,
parent:mainWindow, parent:mainWindow,
modal:true, modal:true,
webPreferences:{nodeIntegration:true,contextIsolation:false} webPreferences:{contextIsolation:true,preload:path.join(__dirname,'popup-preload.js')}
}); });
promptWindow.loadFile(path.join(__dirname,'inactivity-prompt-extended.html')); promptWindow.loadFile(path.join(__dirname,'inactivity-prompt-extended.html'));
@@ -4953,7 +4950,7 @@ function showPauseDialog(){
alwaysOnTop:true, alwaysOnTop:true,
parent:mainWindow, parent:mainWindow,
modal:true, modal:true,
webPreferences:{nodeIntegration:true,contextIsolation:false} webPreferences:{contextIsolation:true,preload:path.join(__dirname,'popup-preload.js')}
}); });
pauseWindow.loadFile(path.join(__dirname,'pause-dialog.html')); pauseWindow.loadFile(path.join(__dirname,'pause-dialog.html'));
@@ -5031,8 +5028,8 @@ function showHTMLKeyboard(){
skipTaskbar:true, skipTaskbar:true,
focusable:false, focusable:false,
webPreferences:{ webPreferences:{
nodeIntegration:true, contextIsolation:true,
contextIsolation:false, preload:path.join(__dirname,'popup-preload.js'),
backgroundThrottling:false backgroundThrottling:false
} }
}); });
@@ -5153,7 +5150,7 @@ function showPinEntry(){
alwaysOnTop:true, alwaysOnTop:true,
parent:mainWindow, parent:mainWindow,
modal:true, modal:true,
webPreferences:{nodeIntegration:true,contextIsolation:false} webPreferences:{contextIsolation:true,preload:path.join(__dirname,'popup-preload.js')}
}); });
pinWindow.loadFile(path.join(__dirname,'pin-entry.html')); pinWindow.loadFile(path.join(__dirname,'pin-entry.html'));
@@ -5798,7 +5795,6 @@ sudo -u "$KIOSK_USER" tee "$KIOSK_DIR/keyboard.html" > /dev/null <<'KBHTML'
</div> </div>
<script> <script>
const { ipcRenderer } = require('electron');
let shiftPressed = false; let shiftPressed = false;
let capsLock = false; let capsLock = false;
@@ -5830,7 +5826,7 @@ sudo -u "$KIOSK_USER" tee "$KIOSK_DIR/keyboard.html" > /dev/null <<'KBHTML'
function typeKey(element) { function typeKey(element) {
const special = element.getAttribute('data-special'); const special = element.getAttribute('data-special');
if (special) { if (special) {
ipcRenderer.send('keyboard-type', special); window.electronAPI.send('keyboard-type', special);
return; return;
} }
@@ -5845,7 +5841,7 @@ sudo -u "$KIOSK_USER" tee "$KIOSK_DIR/keyboard.html" > /dev/null <<'KBHTML'
finalKey = shiftKey; finalKey = shiftKey;
} }
ipcRenderer.send('keyboard-type', finalKey); window.electronAPI.send('keyboard-type', finalKey);
if (shiftPressed) { if (shiftPressed) {
shiftPressed = false; shiftPressed = false;
@@ -5880,13 +5876,13 @@ sudo -u "$KIOSK_USER" tee "$KIOSK_DIR/keyboard.html" > /dev/null <<'KBHTML'
} }
function closeKeyboard() { function closeKeyboard() {
ipcRenderer.send('close-keyboard'); window.electronAPI.send('close-keyboard');
} }
updateKeyDisplay(); updateKeyDisplay();
// Tell main process we're ready // Tell main process we're ready
ipcRenderer.send('keyboard-ready'); window.electronAPI.send('keyboard-ready');
</script> </script>
</body> </body>
</html> </html>
@@ -5991,13 +5987,12 @@ sudo -u "$KIOSK_USER" tee "$KIOSK_DIR/pause-dialog.html" > /dev/null <<'PAUSEHTM
</div> </div>
<script> <script>
const {ipcRenderer} = require('electron');
let timeLeft = 30; let timeLeft = 30;
let countdownInterval; let countdownInterval;
function selectTime(minutes) { function selectTime(minutes) {
clearInterval(countdownInterval); clearInterval(countdownInterval);
ipcRenderer.send('pause-time-selected', minutes); window.electronAPI.send('pause-time-selected', minutes);
} }
function updateCountdown() { function updateCountdown() {
@@ -6100,17 +6095,8 @@ echo "[15/27] Creating PIN entry dialog..."
<div class="info">Default PIN: 1234 (4-8 digits)</div> <div class="info">Default PIN: 1234 (4-8 digits)</div>
</div> </div>
<script> <script>
const {ipcRenderer} = require('electron'); let correctPin = window.electronAPI.readPin();
const fs = require('fs');
const path = require('path');
const pinFile = path.join(__dirname, '.jitsi-pin');
let correctPin = '1234';
let enteredPin = ''; let enteredPin = '';
try {
const stored = fs.readFileSync(pinFile, 'utf8').trim();
if (stored !== 'NOPIN') correctPin = stored;
else correctPin = null;
} catch(e) {}
function updateDisplay() { function updateDisplay() {
const display = document.getElementById('pin-display'); const display = document.getElementById('pin-display');
if (enteredPin.length === 0) { if (enteredPin.length === 0) {
@@ -6137,7 +6123,7 @@ echo "[15/27] Creating PIN entry dialog..."
return; return;
} }
if (correctPin === null || enteredPin === correctPin) { if (correctPin === null || enteredPin === correctPin) {
ipcRenderer.send('pin-correct'); window.electronAPI.send('pin-correct');
} else { } else {
document.getElementById('error').textContent = '❌ Incorrect PIN'; document.getElementById('error').textContent = '❌ Incorrect PIN';
document.getElementById('error').style.display = 'block'; document.getElementById('error').style.display = 'block';
@@ -6145,7 +6131,7 @@ echo "[15/27] Creating PIN entry dialog..."
updateDisplay(); updateDisplay();
} }
} }
function cancel() { ipcRenderer.send('pin-cancelled'); } function cancel() { window.electronAPI.send('pin-cancelled'); }
document.addEventListener('keydown', (e) => { document.addEventListener('keydown', (e) => {
if (e.key >= '0' && e.key <= '9') addDigit(e.key); if (e.key >= '0' && e.key <= '9') addDigit(e.key);
else if (e.key === 'Backspace') backspace(); else if (e.key === 'Backspace') backspace();
@@ -6264,7 +6250,6 @@ echo "[15/27] Creating inactivity prompt..."
</div> </div>
</div> </div>
<script> <script>
const {ipcRenderer} = require('electron');
let count = 15; let count = 15;
const interval = setInterval(() => { const interval = setInterval(() => {
count--; count--;
@@ -6277,13 +6262,13 @@ echo "[15/27] Creating inactivity prompt..."
function imHere(minutes) { function imHere(minutes) {
clearInterval(interval); clearInterval(interval);
console.log('[PROMPT] User selected: '+(minutes===0?'Continue':minutes+' minutes')); console.log('[PROMPT] User selected: '+(minutes===0?'Continue':minutes+' minutes'));
ipcRenderer.send('user-still-here', minutes); window.electronAPI.send('user-still-here', minutes);
} }
function goHome() { function goHome() {
clearInterval(interval); clearInterval(interval);
console.log('[PROMPT] User requested immediate home return'); console.log('[PROMPT] User requested immediate home return');
ipcRenderer.send('user-still-here', -1); window.electronAPI.send('user-still-here', -1);
} }
document.addEventListener('keydown', (e) => { document.addEventListener('keydown', (e) => {
@@ -6302,6 +6287,27 @@ INACTHTML
echo "1234" | sudo -u "$KIOSK_USER" tee "$KIOSK_DIR/.jitsi-pin" >/dev/null echo "1234" | sudo -u "$KIOSK_USER" tee "$KIOSK_DIR/.jitsi-pin" >/dev/null
sudo -u "$KIOSK_USER" chmod 600 "$KIOSK_DIR/.jitsi-pin" sudo -u "$KIOSK_USER" chmod 600 "$KIOSK_DIR/.jitsi-pin"
log_success "Default PIN: 1234" log_success "Default PIN: 1234"
echo "[15.5/27] Creating popup-preload.js..."
sudo -u "$KIOSK_USER" tee "$KIOSK_DIR/popup-preload.js" > /dev/null <<'POPUPPRELOAD'
const{contextBridge,ipcRenderer}=require('electron');
const crypto=require('crypto');
const fs=require('fs');
const path=require('path');
contextBridge.exposeInMainWorld('electronAPI',{
send:(channel,data)=>ipcRenderer.send(channel,data),
on:(channel,cb)=>{ipcRenderer.on(channel,(_e,...args)=>cb(...args));},
once:(channel,cb)=>{ipcRenderer.once(channel,(_e,...args)=>cb(...args));},
hashPassword:(pass)=>crypto.createHash('sha256').update(pass).digest('hex'),
readPin:()=>{
try{
const stored=fs.readFileSync(path.join(__dirname,'.jitsi-pin'),'utf8').trim();
return stored==='NOPIN'?null:stored;
}catch(e){return'1234';}
}
});
POPUPPRELOAD
########################################################################### ###########################################################################
############################start-preload################################## ############################start-preload##################################
########################################################################### ###########################################################################
@@ -8747,7 +8753,6 @@ install_html_keyboard() {
</div> </div>
<script> <script>
const { ipcRenderer } = require('electron');
let shiftPressed = false; let shiftPressed = false;
let capsLock = false; let capsLock = false;
@@ -8761,7 +8766,7 @@ install_html_keyboard() {
function typeKey(element) { function typeKey(element) {
const special = element.getAttribute('data-special'); const special = element.getAttribute('data-special');
if (special) { if (special) {
ipcRenderer.send('keyboard-type', special); window.electronAPI.send('keyboard-type', special);
return; return;
} }
@@ -8776,7 +8781,7 @@ install_html_keyboard() {
finalKey = shiftKey; finalKey = shiftKey;
} }
ipcRenderer.send('keyboard-type', finalKey); window.electronAPI.send('keyboard-type', finalKey);
if (shiftPressed) { if (shiftPressed) {
shiftPressed = false; shiftPressed = false;
@@ -8828,7 +8833,7 @@ install_html_keyboard() {
} }
function closeKeyboard() { function closeKeyboard() {
ipcRenderer.send('close-keyboard'); window.electronAPI.send('close-keyboard');
} }
updateKeyDisplay(); updateKeyDisplay();
@@ -8960,7 +8965,7 @@ function showHTMLKeyboard(){
frame:false, frame:false,
alwaysOnTop:true, alwaysOnTop:true,
skipTaskbar:true, skipTaskbar:true,
webPreferences:{nodeIntegration:true,contextIsolation:false} webPreferences:{contextIsolation:true,preload:path.join(__dirname,'popup-preload.js')}
}); });
htmlKeyboardWindow.loadFile(path.join(__dirname,'keyboard.html')); htmlKeyboardWindow.loadFile(path.join(__dirname,'keyboard.html'));
@@ -10845,6 +10850,7 @@ upgrade_kiosk() {
# Extract all files using their unique heredoc markers # Extract all files using their unique heredoc markers
extract_file 'tee.*main\.js.*MAINJS' 'MAINJS' "$KIOSK_DIR/main.js" extract_file 'tee.*main\.js.*MAINJS' 'MAINJS' "$KIOSK_DIR/main.js"
extract_file 'tee.*preload\.js.*PRELOAD' 'PRELOAD' "$KIOSK_DIR/preload.js" extract_file 'tee.*preload\.js.*PRELOAD' 'PRELOAD' "$KIOSK_DIR/preload.js"
extract_file 'tee.*popup-preload\.js.*POPUPPRELOAD' 'POPUPPRELOAD' "$KIOSK_DIR/popup-preload.js"
extract_file 'tee.*keyboard\.html.*KBHTML' 'KBHTML' "$KIOSK_DIR/keyboard.html" extract_file 'tee.*keyboard\.html.*KBHTML' 'KBHTML' "$KIOSK_DIR/keyboard.html"
extract_file 'tee.*pause-dialog\.html.*PAUSEHTML' 'PAUSEHTML' "$KIOSK_DIR/pause-dialog.html" extract_file 'tee.*pause-dialog\.html.*PAUSEHTML' 'PAUSEHTML' "$KIOSK_DIR/pause-dialog.html"
extract_file 'tee.*pin-entry\.html.*PINHTML' 'PINHTML' "$KIOSK_DIR/pin-entry.html" extract_file 'tee.*pin-entry\.html.*PINHTML' 'PINHTML' "$KIOSK_DIR/pin-entry.html"