@mh-cbon/aghfabsowecwn

2.0.4 • Public • Published

aghfabsowecwn - aka wtf

A Giant Hack For A Better Support Of Windows Elevated Commands With Node

Introduction

This module gives you a more complete support to run windows commands with elevated privileges.

What s the problem

Running windows elevated command with node is not simple,

  • loss of FD[0,1,2]
  • loss of return codes
  • loss of control over the elevated process

Solutions exists on npm, but they all have drawbacks such as,

  • provide only a mimic of child_process.exec,
  • no support of child_process.spawn
  • poorly reports about UAC validation
  • poorly reports about exit codes
  • no support to call methods on elevated process such as kill
  • no support to listen emitted evens by the elevated process

Find out more at

It s also more than possible that alternatives solution using binaries exists,

I m not aware of them / I wish not to use a black box.

What s this module enhancements

This module provides

  • support for child_process.spawn
  • support for commons fds : stdin, stdout, stderr
  • support for methods call : kill
  • support to detect unvalidated UAC
  • support for return codes
  • support of elevated process events
  • does not need any sort of binary
  • automatic fix of cwd for the elevated process

Install

npm i @mh-cbon/aghfabsowecwn --save

Usage

spawn

var spawn = require('@mh-cbon/aghfabsowecwn').spawn;

var opts = {
  bridgeTimeout: 5000,    // a timeout to detect that UAC was not validated, defaults to 3 minutes
  stdio: 'pipe',          // How do you want your pipes ?
  env:{
    'FORCE_COLOR':1,  // example, enable chalk coloring  
    'DEBUG': '*'      // example, enable visionmedia/debug output
  }
}

var child = spawn(process.argv[0], [__dirname + '/test/utils/stdin.js'], opts);

child.on('started', function () {
  console.log('===> child pid=%s', child.pid)
})

child.on('close', function (code) {
  console.log('===> child close code=%s', code)
})

child.on('exit', function (code) {
  console.log('===> child exit code=%s', code)
})

// if UAC is not validated, or refused, an error is emitted
child.on('error', function (error) {
  console.log('===> child error=%s', error)
  console.log('===> child error=%j', error)
  if (err.code==='ECONNREFUSED') console.log('UAC was probably not validated.')
})

child.stdout.pipe(process.stdout)
child.stderr.pipe(process.stderr)

child.stdin.write('some');
// child.stdin.end();
child.once('started', function () {
  setTimeout(function () {
    child.kill();
  }, 1000)
})

exec

var exec = require('@mh-cbon/aghfabsowecwn').exec;

var opts = {
  bridgeTimeout: 5000,    // a timeout to detect that UAC was not validated, defaults to 3 minutes
  stdio: 'pipe',          // How do you want your pipes ?
  env:{
    'FORCE_COLOR':1,  // example, enable chalk coloring  
    'DEBUG': '*'      // example, enable visionmedia/debug output
  }
}

var child = exec('ls -al', opts, function (err, stdout, stderr) {
  console.log('===> child error=%s', error)
  console.log('===> child error=%j', error)
  if (err.code==='ECONNREFUSED') console.log('UAC was probably not validated.')
  console.log("stdout=%s", stdout);
  console.error("stderr=%s", stderr);
});

child.on('started', function () {
  console.log('===> child pid=%s', child.pid)
})

child.on('close', function (code) {
  console.log('===> child close code=%s', code)
})

child.on('exit', function (code) {
  console.log('===> child exit code=%s', code)
})

// if UAC is not validated, or refused, an error is emitted
child.on('error', function (error) {
  console.log('===> child error=%s', error)
  console.log('===> child error=%j', error)
  if (err.code==='ECONNREFUSED') console.log('UAC was probably not validated.')
})

Internals

This modules is a giant hack because it uses overkill techniques to achieve something which seems rather simple.

The short story is,

  • the module spawns a server on a random address with an elevated process,
  • a client is spawned and wait for the server to be alive,
  • the client throws an ECONNREFUSED error when UAC was not accepted
  • the client create an instance of FakeChild,
  • the client connects multiple sockets with the server to emulate pipes, events, methods, FD
  • the client sends the command to run to the elevated server process
  • the server runs the command and exports any signal to the client
  • the client forwards the signals to the fake child instance

The server help to escape signals and data from the elevated child to the userland (socket to pipe / pipe to socket).

FD[0,1,2]
stderr        [user] <=== [server] <=== [elevated]
stdout        [user] <=== [server] <=== [elevated]
stdin         [user] ===> [server] ===> [elevated]

Method calls
controlin     [user] ===> [server] ===> [elevated]

emitted events && set properties
controlout    [user] <=== [server] <=== [elevated]

Other notes

  • remember that the remote child is not running with a TTY, so the behavior may be a bit different (no color support for example)
  • spawn child properties/methods call are available only once started event is emitted.

Todos

  • write the tests

Read more

Dependencies (3)

Dev Dependencies (2)

Package Sidebar

Install

npm i @mh-cbon/aghfabsowecwn

Weekly Downloads

5

Version

2.0.4

License

MIT

Last publish

Collaborators

  • mh-cbon