Call Host commands from a browser

A method for replacing old ActiveX which is no longer supported in IE.

General approach: Install a daemon on the desktop and use a Websocket to communicate between a page and the server in order to launch local commands.

Beware of the potential risks of this method because we open a breach on the PC but we can still control the level of risk.
ie: Because a malicious js code could call the websocket, I would advise to improve this prototype by adding a token (One-Time Password) which will be shared between the server and the genuine page.
Never allow to send directly a windows/DOS command !

In the following case, the dameon is implemented in node.js

  • Install Node.js
  • Install modules for webSocket, FileSystem and Node Commands (ws, fs and node-cmd)
  • Write the js script server which will listen for the commands to be executed
  • Write the js script to be included in the html page. The js will send requests through a websocket.

Code of the Node.js server

// ------------------------------------------------------------------
// serverws.js
// v0.1
// GPM FACTORY
// Nov 2023
// 
// Websocket server used for creating files and 
// triggering a limited set of OS commands 
// usage : node serversws.js
// ------------------------------------------------------------------

const WebSocket = require('ws')
const fs = require('fs');
const nodeCmd = require('node-cmd')
let content
let fidir = ''
const LOG = 1       // 1= Yes, 0= No
const PORT = '8088'
const U_DIR = 'C:/_main/Projets/chronoA/out/'  
const C_DIR = 'C:/_main/Projets/chronoB/out/'      
const C1 = 'DIR'   // 'C:/temp/print_acrobat.cmd'
//const ss = require('stream-string')  // not needed
const wss = new WebSocket.Server({ port: PORT })

// Each message from client is structured as :
// For a file:
//   #<FILE_TYPE>#<FILE_NAME>#<CONTENT>
//   with <FILE_TYPE> = U or C
// For an OS command:
//  !<COMMAND_NUMBER>

wss.on('connection', ws => {
       
    ws.on('message', function message(data) {
        content = '' + data
        if (content.substring(0,1) == '#') {
            // it's a file content
            // we must detect the type of content 
            let fity = content.substring(1,2)
            
            if (fity == 'U'){        

                fidir = U_DIR
               }
            if (fity == 'C'){       

                fidir = C_DIR
            }   

            let nend = content.indexOf("#",3)
            
            let finame = content.substring(3,nend)
            if (LOG == 1) {
                console.log("file name=" + finame)
            }
            let writeStream = fs.createWriteStream(fidir+finame) 
            writeStream.write(content.substr(nend+1))
            writeStream.end() 
            ws.send('File has been created')
        }
        if (content.substring(0,1) == '!') {
            // it's a command
            // we avoid to pass an arbitrary command because potential securiy issues. Instead, we pass a command type (!TBD)
            cmd = content.substring(1)
            if (LOG == 1) {
                console.log("commande="+ cmd)
            }
            if (cmd == '1') {
                nodeCmd.run(C1, (err, data, stderr) => console.log(data));
            }
            else {
                ws.send('Unknown command')
            }
         }
        if (LOG == 1) {
            console.log('received: %s', data)
        }
    });    


})

Code of the JS script in the HTML page

<SCRIPT LANGUAGE="JavaScript">
	function makefile(){
		var fso;var thefile;


    ws.onopen = () => {
      console.log('Send the chrono to ws');

       finame = 'etiq-<?php echo $_GET["ord_id"]?>.csv'; 
        // #C# means : CHRONO
      msg = '#C#'+ finame + '#' + document.tags.chrono.value;
      ws.send(msg)
    }
    
    ws.onmessage = (message) => {
        alert (message.data);
        console.log('message received', message.data)
    }
    
//    alert(\'Le fichier est crée.\');	
}

About the author

GPM Factory