IMAGINARY / kiosk-browser

Hardened Web Browser with Kiosk-mode
Apache License 2.0
21 stars 2 forks source link

⌘ Command+Q quits kiosk mode, request for password #71

Closed alexboonstra closed 1 year ago

alexboonstra commented 1 year ago

Hi, I'm having fun with kiosk-browser, but I'm finding the ⌘ Command+Q to quit kiosk mode too easy for users. Could it be made so a custom password can be set to exit kiosk mode?

-p [xxxxxxx] to set exit kiosk mode password

porst17 commented 1 year ago

AFAIK, ⌘+Q is a macOS system shortcut and the kiosk-browser is not doing anything to fight against it. The kiosk-browser is supposed to be used with other tools that lock down the system. It is not a complete kiosk-system on its own.

There is no intention to add such functionality to the kiosk-browser. However, there is the powerful mechanism of preload scripts. Put the following snipped into a file, e.g. prompt-to-quit.js. The snippet is a bit lengthy because Electron does not implement the window.prompt() function and we have to implement a platform specific way to ask for user input:

const process = require('process');
const { execFile } = require('node:child_process');
const { app, globalShortcut } = require('@electron/remote');

/***
 * Prompt for a password on macOS. Utilized the `osascript` utility.
 */
async function promptPasswordMacOS(message) {
  const otaScriptText = `
  function promptPassword(message) {
    var app = Application.currentApplication();
    app.includeStandardAdditions = true;
    var okButtonText = "Ok";
    var cancelButtonText = "Cancel";
    var response = app.displayDialog(message, {
      defaultAnswer: "",
      buttons: [cancelButtonText, okButtonText],
      defaultButton: okButtonText,
      hiddenAnswer: true,
    });
    return JSON.stringify(
      response.buttonReturned === okButtonText ? response.textReturned : null
    );
  }

  promptPassword(${JSON.stringify(message)});`;
  return new Promise((resolve, reject) =>
    execFile(
      'osascript',
      ['-l', 'JavaScript', '-e', otaScriptText],
      (error, stdout) => {
        if (error) {
          reject(error);
        } else {
          resolve(JSON.parse(stdout));
        }
      }
    )
  );
}

/***
 * Unfortunately, Electron does not implement the window.prompt() function such
 * that we need to implement a platform specific way of asking for user input.
 */
async function promptPassword(...args) {
  switch (process.platform) {
    case 'darwin':
      return promptPasswordMacOS(...args);
    case 'linux': // TODO
    case 'win32': // TODO
    default:
      // see https://nodejs.org/api/process.html#process_process_platform
      return null;
  }
}

async function promptToQuit() {
  const password = 'secret';
  while (true) {
    const input = await promptPassword(
      'Enter the password to exit kiosk mode:'
    );
    console.log(input);
    if (input === null) break;

    if (input === password) {
      app.quit();
      break;
    } else {
      window.alert('Wrong password. Please try again.');
    }
  }
}

// different platforms may use different keyboard shortcuts to quit applications
switch (process.platform) {
  case 'darwin':
    globalShortcut.register('Command+Q', promptToQuit);
  case 'linux': // TODO
  case 'win32': // TODO
  default:
  // see https://nodejs.org/api/process.html#process_process_platform
  // TODO
}

Then launch the kiosk-browser with a preload script option:

kiosk-browser --preload prompt-to-quit.js

Now, when pressing ⌘+Q, the kiosk-browser will open a dialog box to enter the password and only quit if it is correct. Note that we are registering a system-wide keyboard shortcut, i.e. this also breaks ⌘+Q for all other application while the kiosk-browser is running.