Socket
Socket
Sign inDemoInstall

node-windows

Package Overview
Dependencies
4
Maintainers
1
Versions
23
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.1.12 to 0.1.13

bin/winsw/winsw.exe

165

lib/daemon.js

@@ -101,14 +101,31 @@ /**

get: function(){
var wrapperArgs = [
'--file', this.script,
'--log', this.name + ' ' + 'wrapper',
'--grow', this.grow,
'--wait', this.wait,
'--maxrestarts', this.maxRestarts,
'--abortonerror', (this.abortOnError==true?'y':'n'),
'--stopparentfirst', this.stopparentfirst
];
if (this.maxRetries!==null)
{
wrapperArgs.push('--maxretries');
wrapperArgs.push(this.maxRetries);
}
return require('./winsw').generateXml({
name: this.name,
id: this._exe,
script: '"'+wrapper+'" -f "'+this.script+'" -l "'+this.name+'" -g '+this.grow
+' -w '+this.wait+(this.maxRetries!==null?' -m '+this.maxRetries:'')
+' -r '+this.maxRestarts+' -a '+(this.abortOnError==true?'y':'n')
+ (config.cwd ? ' -d "'+config.cwd+'"' : ''),
nodeOptions: '--harmony',
script: wrapper,
wrapperArgs: wrapperArgs,
description: this.description,
logpath: this.logpath,
env: config.env,
flags: config.flags,
execPath: this.execPath
logOnAs: this.logOnAs,
workingdirectory: this.workingdirectory,
stopparentfirst: this.stopparentfirst,
stoptimeout: this.stoptimeout
});

@@ -136,2 +153,25 @@ }

},
/**
* @cfg {Boolean} [stopparentfirst=false]
* Allow the service to shutdown cleanly.
*/
stopparentfirst: {
enumerable: true,
writable: false,
configurable: false,
value: config.stopparentfirst
},
/**
* @cfg {Number} [stoptimeout=30]
* How long to wait in seconds before force killing the application.
* This only takes effect when stopparentfirst is enabled.
*/
stoptimeout: {
enumerable: true,
writable: false,
configurable: false,
value: config.stoptimeout || 30
},

@@ -275,30 +315,30 @@ /**

/**
* @property {Object} [user]
* If you need to specify a specific user or particular credentials to manage a service, the following
* attributes may be helpful.
*
* The `user` attribute is an object with three keys: `domain`,`account`, and `password`.
* This can be used to identify which user the service library should use to perform system commands.
* By default, the domain is set to the local computer name, but it can be overridden with an Active Directory
* or LDAP domain. For example:
*
* **app.js**
*
* var Service = require('node-windows').Service;
*
* // Create a new service object
* var svc = new Service({
* name:'Hello World',
* script: require('path').join(__dirname,'helloworld.js')
* });
*
* svc.user.domain = 'mydomain.local';
* svc.user.account = 'username';
* svc.user.password = 'password';
* ...
*
* Both the account and password must be explicitly defined if you want the service module to
* run commands as a specific user. By default, it will run using the user account that launched
* the process (i.e. who launched `node app.js`).
*/
* @property {Object} [user]
* If you need to specify a specific user or particular credentials to manage a service, the following
* attributes may be helpful.
*
* The `user` attribute is an object with three keys: `domain`,`account`, and `password`.
* This can be used to identify which user the service library should use to perform system commands.
* By default, the domain is set to the local computer name, but it can be overridden with an Active Directory
* or LDAP domain. For example:
*
* **app.js**
*
* var Service = require('node-windows').Service;
*
* // Create a new service object
* var svc = new Service({
* name:'Hello World',
* script: require('path').join(__dirname,'helloworld.js')
* });
*
* svc.user.domain = 'mydomain.local';
* svc.user.account = 'username';
* svc.user.password = 'password';
* ...
*
* Both the account and password must be explicitly defined if you want the service module to
* run commands as a specific user. By default, it will run using the user account that launched
* the process (i.e. who launched `node app.js`).
*/
user: {

@@ -314,3 +354,57 @@ enumerable: false,

},
/**
* @property {Object} [logOnAs]
* If you need to specify a specific user or particular credentials for the service log on as once installed, the following
* attributes may be helpful.
*
* The `logOnAs` attribute is an object with four keys: `domain`,`account`, `password`, and `mungeCredentialsAfterInstall`.
* This can be used to identify which user the service should run as once installed.
*
* If no account and password is specified, the logOnAs property is not used and the service will run as the "Local System" account.
* If account and password is specified, but domain is not specified then the domain is set to the local computer name, but it can be overridden with an Active Directory
* or LDAP domain. For example:
*
* **app.js**
*
* var Service = require('node-windows').Service;
*
* // Create a new service object
* var svc = new Service({
* name:'Hello World',
* script: require('path').join(__dirname,'helloworld.js')
* });
*
* svc.logOnAs.domain = 'mydomain.local';
* svc.logOnAs.account = 'username';
* svc.logOnAs.password = 'password';
* ...
*
* Both the account and password must be explicitly defined if you want the service to log on as that user,
* otherwise the Local System account will be used.
*/
logOnAs: {
enumerable: false,
writable: true,
configurable: false,
value: {
account: null,
password: null,
domain: process.env.COMPUTERNAME,
mungeCredentialsAfterInstall: true
}
},
/**
* @property {String} [workingdirectory]
* The full path to the working directory that the service process
* should launch from. If this is omitted, it will default to the
* current processes working directory.
*/
workingdirectory: {
enumerable: false,
writable: true,
configurable: false,
value: process.cwd()
},
// Optionally provide a sudo password.

@@ -497,4 +591,5 @@ sudo: {

// Remove the executable
// Remove the executable and executable .NET runtime config file
rm(me.id+'.exe');
rm(me.id+'.exe.config');

@@ -501,0 +596,0 @@ // Remove all other files

@@ -19,3 +19,3 @@ /**

if (require('os').platform().indexOf('win32') < 0){
throw 'ngn-windows is only supported on Windows.';
throw 'node-windows is only supported on Windows.';
}

@@ -22,0 +22,0 @@

@@ -11,3 +11,4 @@ module.exports = {

* - *name* The descriptive name of the service.
* - *script* The absolute path of the node.js script. i.e. `C:\path\to\myService.js`
* - *script* The absolute path of the node.js server script. i.e. in this case
* it's the wrapper script, not the user's server script.
*

@@ -17,3 +18,4 @@ * Optional attributes include

* - *description* The description that shows up in the service manager.
* - *flags* Any flags that should be passed to node. Defaults to `--harmony` to add ES6 support.
* - *nodeOptions* Array or space separated string of node options (e.g. '--harmony')
* - *wrapperArgs* additional arguments to pass to wrapper script to control restarts, etc.
* - *logmode* Valid values include `rotate` (default), `reset` (clear log), `roll` (move to .old), and `append`.

@@ -24,53 +26,109 @@ * - *logpath* The absolute path to the directory where logs should be stored. Defaults to the current directory.

* environment variables to pass to the process. The object might look like `{name:'HOME',value:'c:\Windows'}`.
* - *logOnAs* A key/value object that contains the service logon credentials.
* The object might look like `{account:'user', password:'pwd', domain:'MYDOMAIN'}
* If this is not included or does not have all 3 members set then it is not used.
* - *workingdirectory* optional working directory that service should run in.
* If this is not included, the current working directory of the install process
* is used.
*/
generateXml: function(config){
generateXml: function(config)
{
var xml;
// Set default values
config = config || {};
config.description = config.description || '';
config.flags = config.flags || '--harmony';
config.logmode = 'rotate';
config.execPath = config.execPath || process.execPath;
// add multiple "tag" items to the xml
// if input is an array, add each element of the array, if it's a string,
// split it around splitter and add each one
// if input is null or undefined do nothing
function multi(tag, input, splitter)
{
// do nothing if no input
if (input===undefined || input===null) {
return;
}
// Initial template
var xml = '<service><id>'
+config.id
+'</id><name>'
+config.name
+'</name><description>'
+config.description
+'</description><executable>' + config.execPath + '</executable><arguments>'
+config.flags
+' '+config.script
+'</arguments><logmode>'
+config.logmode
+'</logmode>';
if (!(input instanceof Array)) {
input = input.split(splitter||',');
}
input.forEach(function(val) {
var ele={};
ele[tag]=String(val).trim();
xml.push(ele);
});
}
// Make sure required configuration items are present
if (!config || !config.id || !config.name || !config.script)
{
throw "WINSW must be configured with a minimum of id, name and script";
}
// create json template of xml
// only the portion of the xml inside the top level 'service' tag
xml = [
{id: config.id},
{name: config.name},
{description: config.description||''},
{executable: process.execPath},
{logmode: config.logmode||'rotate'}
];
multi('argument',config.nodeOptions, ' ');
xml.push({argument:config.script.trim()});
multi('argument',config.wrapperArgs,' ');
// Optionally add log path
if (config.logpath) {
xml += '<logpath>'+config.logpath+'</logpath>';
xml.push({logpath : config.logpath});
}
// Optionally add service dependencies
if (config.dependencies){
config.dependencies = (config.dependencies instanceof Array == true) ? config.dependencies : config.dependencies.split(',');
config.dependencies.forEach(function(dep){
xml += '<depend>'+dep.trim()+'</depend>';
});
// Optionally add stopparentprocessfirst
if (config.stopparentfirst) {
xml.push({stopparentprocessfirst: config.stopparentfirst});
}
// Optionally set the stoptimeout
if (config.stoptimeout) {
xml.push({stoptimeout: config.stoptimeout + 'sec'});
}
// Optionally add service dependencies
multi('depend',config.dependencies);
// Optionally add environment values
if (config.env){
config.env = (config.env instanceof Array == true) ? config.env : [config.env];
if (config.env) {
config.env = (config.env instanceof Array == true) ?
config.env : [config.env];
config.env.forEach(function(env){
xml += '<env name="'+env.name+'" value="'+env.value+'" />';
xml.push({env: {_attr: {name:env.name, value:env.value}}});
});
}
xml += "</service>";
// optionally set the service logon credentials
if (config.logOnAs && config.logOnAs.account && config.logOnAs.password &&
config.logOnAs.domain)
{
xml.push({
serviceaccount: [
{domain: config.logOnAs.domain},
{user: config.logOnAs.account},
{password: config.logOnAs.password}
]
});
}
return xml;
// if no working directory specified, use current working directory
// that this process was launched with
xml.push({workingdirectory: config.workingdirectory || process.cwd()});
// indent resultant xml with tabs, and use windows newlines for extra readability
return require('xml')({service:xml}, {indent: '\t'}).replace(/\n/g,'\r\n');
},
/**
* Copy install version of winsw.exe to specific renamed version according to
* the service id. Also copy .exe.config file that allows it to run under
* .NET 4+ runtime on newer versions of windows.
* (see https://github.com/kohsuke/winsw#net-runtime-40)
*
* @method createExe

@@ -85,6 +143,6 @@ * Create the executable

*/
createExe: function(name,dir,callback){
createExe: function(name,dir,callback) {
var fs = require('fs'), p = require('path');
if (typeof dir === 'function'){
if (typeof dir === 'function') {
callback = dir;

@@ -96,12 +154,13 @@ dir = null;

var origin = p.join(__dirname,'..','bin','winsw','x'+(require('os').arch().indexOf('64')>0 ? '64':'86'),'winsw.exe'),
dest = p.join(dir,name.replace(/[^\w]/gi,'').toLowerCase()+'.exe'),
data = fs.readFileSync(origin,{encoding:'binary'});
var exeOrigin = p.join(__dirname,'..','bin','winsw','winsw.exe'),
cfgOrigin = p.join(__dirname,'..','bin','winsw','winsw.exe.config'),
exeDest = p.join(dir,name.replace(/[^\w]/gi,'').toLowerCase()+'.exe'),
cfgDest = p.join(dir,name.replace(/[^\w]/gi,'').toLowerCase()+'.exe.config'),
exeData = fs.readFileSync(exeOrigin,{encoding:'binary'}),
cfgData = fs.readFileSync(cfgOrigin,{encoding:'binary'});
fs.writeFileSync(dest,data,{encoding:'binary'});
fs.writeFileSync(exeDest,exeData,{encoding:'binary'});
fs.writeFileSync(cfgDest,cfgData,{encoding:'binary'});
callback && callback();
//require('child_process').exec('Icacls "'+dest+'" /grant Everyone:(F)',callback)
//require('child_process').exec('copy "'+origin+'" /y /v /b "'+dest+'" /b',callback);
}
}
}

@@ -52,2 +52,8 @@ // Handle input parameters

})
.default('stopparentfirst', 'no')
.alias('s', 'stopparentfirst')
.describe('stopparentfirst', 'Allow the script to exit using a shutdown message.')
.check(function(argv){
return ['y','n','yes','no'].indexOf(argv.a.trim().toLowerCase()) >= 0;
})
.argv,

@@ -81,3 +87,3 @@ log = new Logger(argv.e == undefined ? argv.l : {source:argv.l,eventlog:argv.e}),

// Hack to force the wrapper process to stay open by launching a ghost socket server
var server = require('net').createServer().listen(0, '127.0.0.1');
var server = require('net').createServer().listen();

@@ -88,4 +94,4 @@ /**

*/
var monitor = function(exit){
if(!child.pid||exit){
var monitor = function() {
if(!child || !child.pid) {

@@ -107,6 +113,7 @@ // If the number of periodic starts exceeds the max, kill the process

} else {
launch();
launch('warn', 'Restarted ' + wait + ' msecs after unexpected exit; attempts = ' + attempts);
}
},wait);
} else {
// reset attempts and wait time
attempts = 0;

@@ -121,10 +128,16 @@ wait = argv.w * 1000;

* A method to start a process.
* logLevel - optional logging level (must be the name of a function the the Logger object)
* msg - optional msg to log
*/
var launch = function(){
var launch = function(logLevel, msg) {
if (forcekill){
if (forcekill) {
log.info("Process killed");
return;
}
log.info('Starting '+argv.f);
//log.info('Starting '+argv.f);
if (logLevel && msg) {
log[logLevel](msg);
}

@@ -144,2 +157,3 @@ // Set the start time if it's null

if (argv.d) opts.cwd = argv.d;
if (argv.s) opts.detached = true;
child = fork(script,opts);

@@ -156,6 +170,9 @@

//server.unref();
} else if (forcekill) {
process.exit();
}
child = null;
// Monitor the process
monitor(true);
monitor();
});

@@ -166,11 +183,10 @@ };

forcekill = true;
child.kill();
/*if (child.pid) {
require('child_process').exec('taskkill /F /PID '+child.pid,function(){
process.exit(0);
});
}*/
if (argv.s) {
child.send('shutdown');
} else {
child.kill();
}
}
process.on('exit',killkid);
process.on('exit', killkid);
process.on("SIGINT", killkid);

@@ -180,2 +196,2 @@ process.on("SIGTERM", killkid);

// Launch the process
launch();
launch('info', 'Starting ' + argv.f);
{
"name": "node-windows",
"version": "0.1.12",
"version": "0.1.13",
"description": "Support for Windows services, event logging, UAC, and several helper methods for interacting with the OS.",

@@ -25,3 +25,4 @@ "keywords": [

"dependencies": {
"optimist": "~0.6.0"
"optimist": "~0.6.0",
"xml": "0.0.12"
},

@@ -28,0 +29,0 @@ "readmeFilename": "README.md",

@@ -508,2 +508,2 @@ # Update (5/21/15)

TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc