Skip to content

Commit

Permalink
Merge pull request #678 from prey/action-for-update-winsvc
Browse files Browse the repository at this point in the history
Action for update winsvc
  • Loading branch information
SoraKenji authored Oct 24, 2022
2 parents 30a2403 + d5b78b1 commit 9dce9de
Show file tree
Hide file tree
Showing 2 changed files with 324 additions and 9 deletions.
110 changes: 101 additions & 9 deletions lib/agent/updater.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
var join = require('path').join,
exists = require('fs').exists,
common = require('./common'),
logger = common.logger.prefix('updater'),
system = common.system,
child_process = require('child_process'); // need to use child_process for stubbing to work in test
const { eq } = require('semver');
var join = require('path').join,
exists = require('fs').exists,
common = require('./common'),
logger = common.logger.prefix('updater'),
system = common.system,
child_process = require('child_process'),
os = require('os'),
exec = child_process.exec,
needle = require('needle'),
updater_path = join(system.paths.package, 'bin', 'updater.exe'),
sys_win = require('./../system/windows/');

var timer, timer2; // for interval check
exports.upgrading = false;
Expand Down Expand Up @@ -32,6 +38,7 @@ var update_client = function(new_version, cb) {
var bin_path = system.paths.package_bin; // /foo/bar/bin/prey
var args = ['config', 'upgrade', new_version];
}

exports.upgrading = true;

var let_the_child_go = function() {
Expand Down Expand Up @@ -115,7 +122,50 @@ var update_client = function(new_version, cb) {
});
}

/**
* Verify if winsvc must be updated
* @param {object} cb - a callback function
*/
exports.check_for_update_winsvc = (cb) => {

/** Skip this block if OS is not windows. */
if (os.platform() != 'win32')
return cb(new Error('Action only allowed on Windows'));

/** Get the current version of winsvc running on the device. */
sys_win.get_winsvc_version((err, current_service_version) => {
if (err) return cb(new Error("Error to get winsvc version"));

if (!current_service_version) {
return cb(new Error("Error to get current winsvc version."));
}

/** Get the latest version of winsvc. */
exports.get_stable_version_winsvc((err, service_version_stable) => {
if (err) return cb(new Error("Error to get stable version"));

logger.notice('New version found winsvc: ' + service_version_stable);

/** check if device is running the latest version. */
if (service_version_stable && eq(current_service_version, service_version_stable)) {
logger.notice('Nothing to do. latest version already installed. ' + service_version_stable);
return cb(null, true)
}

/** Perform the update. */
exports.update_winsvc(updater_path + " -v=" + current_service_version, (err_update) => {
if (err_update)
return cb(new Error("error to update winsvc," + err_update.message))

return cb(null, true)
})
})

})
}

var check_for_update = function(cb) {

if (!exports.check_enabled || exports.upgrading) {
if (cb && typeof cb == 'function') return cb();
else return;
Expand All @@ -130,13 +180,19 @@ var check_for_update = function(cb) {
common.package.new_version_available(branch, common.version, function(err, new_version) {
if (err || !new_version) {
common.package.check_update_success(common.version, versions_path, function(err) {

return cb && cb(err || new Error('Theres no new version available'));
})
} else {
logger.notice('New version found: ' + new_version);
update_client(new_version, cb);
}
})

exports.check_for_update_winsvc((err,is_updated) => {
if(err) logger.info(err.message);
if(is_updated) logger.info("winsvc updated ");
});
}

exports.check = function(id, target, opts, cb) {
Expand All @@ -163,7 +219,9 @@ exports.check = function(id, target, opts, cb) {
if (exports.upgrading) logger.warn('Already running upgrade process.')

common.package.delete_attempts((err) => {
last_time = null;
if(err)
logger.error(err)

check_for_update((err) => {
done(err);
});
Expand Down Expand Up @@ -198,6 +256,16 @@ exports.check = function(id, target, opts, cb) {
common.package.restart_client();
done();
break;

case "update-winsvc":
// update winsvc
logger.info("command updating winsvc");
exports.check_for_update_winsvc((err,is_updated) => {
if(err) logger.info(err.message);
if(is_updated) logger.info("winsvc updated from command");
done();
});
break;

default:
logger.warn("Invalid target for upgrade command")
Expand All @@ -210,7 +278,6 @@ exports.check_every = function(interval, cb) {
if (!system.paths.versions)
return cb && cb(no_versions_support_error());

var interval = interval || 3 * 60 * 60 * 1000; // three hours by default
timer = setInterval(() => {
exports.check_enabled = true;
exports.upgrading = false;
Expand All @@ -220,10 +287,35 @@ exports.check_every = function(interval, cb) {

exports.stop_checking = function() {
if (timer) clearInterval(timer);
if (timer2) clearInterval(timer2);
if (timer2) clearInterval(timer2);
timer = null;
timer2 = null;
}

exports.update_winsvc = (path,cb) => {
exec(path, (err, pid) => {
logger.info("executing service windows update!"+ path)
if (err) return cb(err)
return cb(null,pid)
})
}

exports.get_stable_version_winsvc = function(cb) {
let //releases_host = 'http://172.200.2.6',
//releases_url = releases_host + '/prey-releases/winsvc/',
releases_host = 'https://downloads.preyproject.com',
releases_url = releases_host + '/prey-client-releases/winsvc/',
latest_text = 'latest.txt';

let key = common.config.get('control-panel.device_key').toString() || null;
var options = {
headers: { 'resource-dk': key }
}
needle.get(releases_url + latest_text, key ? options : null, function(err, resp, body) {
var ver = body && body.toString().trim();
cb(err, ver);
});
}

exports.check_for_update = check_for_update;
exports.logger = logger;
223 changes: 223 additions & 0 deletions test/lib/agent/updating_winsvc_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
/* eslint-disable no-undef */
var join = require('path').join,
helpers = require(join('..', '..', 'helpers')),
should = require('should'),
sinon = require('sinon'),
assert = require('assert'),
sys_index_path = helpers.lib_path('system'),
sys_index = require(sys_index_path),
sys_win = require(join(sys_index_path, 'windows')),
os = require('os'),
sending = { count: 0 }
updater = require(helpers.lib_path('agent', 'updater'));

function startCheckUpdateWinsvc(number) {
setInterval(function () {
sending.count += number;
updater.check_for_update_winsvc(() => {
})
}, 100);
}

describe('when os != windows', () => {
before(() => {
sys_index.os_name = "mac"
platform_stub = sinon.stub(os, 'platform').callsFake(() => { return 'mac'; });
})

after(() => {
platform_stub.restore();
})

it('returns an error', (done) => {
updater.check_for_update_winsvc((err) => {
should.exist(err);
err.message.should.containEql('Action only allowed on Windows');
done();
});
})
})

describe('update winsvcs interval', function () {
before(() => {
sys_index.os_name = "windows"
platform_stub_3 = sinon.stub(os, 'platform').callsFake(() => { return 'win32'; });
})

describe('updater winsvc', function () {

beforeEach(function () {
sys_index.os_name = "windows"
this.clock = sinon.useFakeTimers();
});

afterEach(function () {
this.clock = sinon.restore();
});

it('should be sent once', function () {
startCheckUpdateWinsvc(1);
//advance the clock
this.clock.tick(100);
this.clock.tick(100);
assert.equal(sending.count, 2);
});
})

})

describe('when os is windows', () => {
before(() => {
sys_index.os_name = "windows"
sys_index.check_service = sys_win.check_service;
sys_index.run_as_admin = sys_win.run_as_admin;
platform_stub = sinon.stub(os, 'platform').callsFake(() => { return 'win32'; });
})

after(() => {
platform_stub.restore();
})

describe('when get_winsvc_version return error', () => {

var get_winsvc_version_stub;
before(() => {
get_winsvc_version_stub = sinon.stub(sys_win, 'get_winsvc_version').callsFake((cb) => {
cb(new Error('No winsvc version found.'));
});
})

after(() => {
get_winsvc_version_stub.restore();
})

it('should return error to get os edition', (done) => {
updater.check_for_update_winsvc((err) => {
should.exist(err);
err.message.should.containEql('Error to get winsvc version');
done();
});
})
})

describe('when get_stable_version_winsvc return error', () => {

var get_winsvc_version_2_1_0_stub;
var get_stable_version_winsvc_error;
before(() => {
get_winsvc_version_2_1_0_stub = sinon.stub(sys_win, 'get_winsvc_version').callsFake((cb) => {
cb(null, "2.0.1");
});
get_stable_version_winsvc_error = sinon.stub(updater, 'get_stable_version_winsvc').callsFake((cb) => {
cb(new Error('Error get_stable_version_winsvc.'));
});
})

after(() => {
get_winsvc_version_2_1_0_stub.restore();
get_stable_version_winsvc_error.restore();
})

it('should return 2.0.1', (done) => {
updater.check_for_update_winsvc((err) => {
should.exist(err);
err.message.should.containEql('Error to get stable version');
done();
});
})
})

describe('when get_stable_version_winsvc return ok and is updated', () => {

var get_winsvc_version_2_0_2_stub;
var get_stable_version_winsvc_ok;
before(() => {
get_winsvc_version_2_0_2_stub = sinon.stub(sys_win, 'get_winsvc_version').callsFake((cb) => {
cb(null, "2.0.2");
});
get_stable_version_winsvc_ok = sinon.stub(updater, 'get_stable_version_winsvc').callsFake((cb) => {
cb(null, "2.0.2");
});

})

after(() => {
get_winsvc_version_2_0_2_stub.restore();
get_stable_version_winsvc_ok.restore();
})

it('should return 2.0.0', (done) => {
updater.check_for_update_winsvc((err) => {
should.not.exist(err);
done();
});
})
})

describe('when get_stable_version_winsvc return ok and not updated and winsvc return error', () => {

var get_winsvc_version_2_0_3_stub;
var get_stable_version_winsvc_ok;
var update_winsvc_error;
before(() => {
get_winsvc_version_2_0_3_stub = sinon.stub(sys_win, 'get_winsvc_version').callsFake((cb) => {
cb(null, "2.0.3");
});
get_stable_version_winsvc_ok = sinon.stub(updater, 'get_stable_version_winsvc').callsFake((cb) => {
cb(null, "2.0.4");
});
update_winsvc_error = sinon.stub(updater, 'update_winsvc').callsFake((path, cb) => {
cb(new Error('Error to update winsvc.'));
});
})

after(() => {
get_winsvc_version_2_0_3_stub.restore();
get_stable_version_winsvc_ok.restore();
update_winsvc_error.restore();
})

it('should return 2.0.4', (done) => {
updater.check_for_update_winsvc((err) => {
should.exist(err);
err.message.should.containEql('error to update winsvc');
done();
});
})
})

describe('when get_stable_version_winsvc return ok and not updated and winsvc update ok', () => {

var get_winsvc_version_2_0_4_stub;
var get_stable_version_winsvc_ok;
var update_winsvc_error;
before(() => {
get_winsvc_version_2_0_4_stub = sinon.stub(sys_win, 'get_winsvc_version').callsFake((cb) => {
cb(null, "2.0.4");
});
get_stable_version_winsvc_ok = sinon.stub(updater, 'get_stable_version_winsvc').callsFake((cb) => {
cb(null, "2.0.5");
});
update_winsvc_error = sinon.stub(updater, 'update_winsvc').callsFake((path, cb) => {
cb(null, true);
});
})

after(() => {
get_winsvc_version_2_0_4_stub.restore();
get_stable_version_winsvc_ok.restore();
update_winsvc_error.restore();
})

it('should return 2.0.4', (done) => {
updater.check_for_update_winsvc((err, isUpdated) => {
should.not.exist(err);
should.exist(isUpdated);
console.log(isUpdated)
done();
});
})
})
})


0 comments on commit 9dce9de

Please sign in to comment.