Skip to content

Commit

Permalink
Merge branch 'develop' into 'master'
Browse files Browse the repository at this point in the history
Develop

See merge request prey/js/prey-node-client!1157
  • Loading branch information
Claudio committed Jan 20, 2025
2 parents d0532b8 + 1a0d067 commit 6355197
Show file tree
Hide file tree
Showing 26 changed files with 1,327 additions and 1,535 deletions.
156 changes: 94 additions & 62 deletions lib/agent/actions/factoryreset/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,50 +10,102 @@ const logger = common.logger.prefix('factoryreset');
const token = require('../../token');
const system = require('../../../system');
const { errorFactoryReset } = require('../../errors');
const factory_reset_options = require('./factory-reset-option');
const factoryResetOptions = require('./factory-reset-option');

const osName = os.platform().replace('darwin', 'mac').replace('win32', 'windows');
let emitter;
let action;
const node_bin = join(system.paths.current, 'bin', 'node');
const file_factory_reset = join(system.paths.current, 'lib', 'agent', 'actions', 'factoryreset', 'bin', 'factory-reset.ps1');
const directory_factory_reset = join(system.paths.current, 'lib', 'agent', 'actions', 'factoryreset', 'bin');
const file_factory_reset_xml = join(directory_factory_reset, 'FactoryReset.xml');

const time_execution = () => {
const nodeBin = join(system.paths.current, 'bin', 'node');
const fileFactoryReset = join(system.paths.current, 'lib', 'agent', 'actions', 'factoryreset', 'bin', 'factory-reset.ps1');
const directoryFactoryReset = join(system.paths.current, 'lib', 'agent', 'actions', 'factoryreset', 'bin');
const fileFactoryResetXml = join(directoryFactoryReset, 'FactoryReset.xml');
const timeExecution = () => {
let now = new Date();
now.setMinutes(now.getMinutes() + 2); // add two minuts
now = new Date(now);
const datetext = now.toTimeString();
const time = datetext.split(' ')[0];
return time;
};

exports.start = function (id, options, cb) {
const osName = os.platform().replace('darwin', 'mac').replace('win32', 'windows');

const dataFirst = {
key: 'device-key',
token: 'token',
logged: false,
dirs: [],
};
const actionFirst = 'advanced-options';
const dataSecond = {
key: 'device-key',
token: 'token',
logged: false,
dirs: [fileFactoryReset, timeExecution(), process.arch, fileFactoryResetXml],
};
const actionSecond = 'factory-reset';
const writeData = (cb) => {
// eslint-disable-next-line consistent-return
fs.writeFile(fileFactoryResetXml, factoryResetOptions.format_file, (errWriteFile) => {
if (errWriteFile) {
const errWrite = errWriteFile;
errWrite.code = 6;
return cb(errWrite);
}
cb(null);
});
};
const postToken = (opts, cb) => {
token.post_token({
action: opts.target,
token: opts.token,
id: opts.messageID,
// eslint-disable-next-line consistent-return
}, (err) => {
if (err) {
const error = err;
error.code = 5;
error.name = errorFactoryReset.find((x) => x.code === error.code).message;
return cb(error);
}
cb(null);
});
};
const runCommandThroughWService = (data, cb) => {
// eslint-disable-next-line consistent-return
system.spawn_as_admin_user(nodeBin, data, (errSpawnFirst, childAction) => {
if (errSpawnFirst) {
const errSpawnFirstData = errSpawnFirst;
errSpawnFirstData.code = 7;
logger.info(`Error executing Factory Reset :${JSON.stringify(errSpawnFirstData)}`);
return cb(errSpawnFirst);
}
if (typeof childAction === 'function') {
return cb(null, childAction);
}
const error = new Error('Admin service not available');
error.code = 4;
error.name = errorFactoryReset.find((x) => x.code === error.code).message;
return cb(error);
});
};
// eslint-disable-next-line consistent-return
exports.start = (id, options, cb) => {
if (osName !== 'windows') {
const error = new Error('Action only allowed on Windows 1O');
error.code = 3;
error.name = errorFactoryReset.find((x) => x.code === error.code).message;
return cb(error);
}

const opts = options || {};
if (!opts || id === undefined || opts.token === undefined || opts.target === undefined) {
const error = new Error('The factory reset data is not valid');
error.code = 2;
error.name = errorFactoryReset.find((x) => x.code === error.code).message;
return cb(error);
}

const finished = function (err, out) {
const finished = (err, out) => {
logger.info('Factory Reset Process initialized!');
let output = null;

if (!err) {
output = {};
if (!out) return emitter.emit('end', id);

if (out && out.error) {
output.data = 1;// error
output.message = out.message;
Expand All @@ -63,56 +115,36 @@ exports.start = function (id, options, cb) {
output.message = 'OK';
}
}
// eslint-disable-next-line consistent-return
if (!emitter) return;
return emitter.emit('end', id, err, output);
};

token.post_token({ action: opts.target, token: opts.token, id: opts.messageID }, (err) => {
if (err) {
const error = err;
error.code = 5;
error.name = errorFactoryReset.find((x) => x.code === error.code).message;
return cb(error);
}

const data = {
key: 'device-key',
token: 'token',
logged: false,
dirs: [file_factory_reset, time_execution(), process.arch, file_factory_reset_xml],
};

action = 'factory-reset';

emitter = new Emitter();
cb(null, emitter);

fs.writeFile(file_factory_reset_xml, factory_reset_options.format_file, (errWriteFile) => {
if (errWriteFile) {
const errWrite = errWriteFile;
errWrite.code = 6;
return cb(errWrite);
}
system.spawn_as_admin_user(node_bin, data, (errSpawn, child) => {
if (errSpawn) {
const errSpawnData = errSpawn;
errSpawnData.code = 7;
logger.info(`Error executing Factory Reset :${JSON.stringify(errSpawnData)}`);
return cb(errSpawn);
}
if (typeof child === 'function') { // only for windows
child(action, data, finished);
} else {
const error = new Error('Admin service not available');
error.code = 4;
error.name = errorFactoryReset.find((x) => x.code === error.code).message;
return cb(error);
}
// eslint-disable-next-line consistent-return
runCommandThroughWService(dataFirst, (err, childAction) => {
if (err) return cb(err);
if (childAction) {
childAction(actionFirst, dataFirst, () => {
// eslint-disable-next-line consistent-return
postToken(opts, (errorPost) => {
if (err) return cb(errorPost);
emitter = new Emitter();
cb(null, emitter);
// eslint-disable-next-line consistent-return
writeData((errorWrite) => {
if (errorWrite) return cb(errorWrite);
// eslint-disable-next-line consistent-return
runCommandThroughWService(dataSecond, (errorSecond, childActionSecond) => {
if (errorSecond) return cb(errorSecond);
if (childActionSecond) {
childActionSecond(actionSecond, dataSecond, finished);
}
});
});
});
});
});
}
});
};

exports.stop = function () {
exports.stop = () => {
emitter = null;
};
30 changes: 23 additions & 7 deletions lib/agent/actions/logretrieval/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ const { paths } = common.system;
const osName = process.platform.replace('win32', 'windows').replace('darwin', 'mac');
const keys = require('../../control-panel/api/keys');

const { retrieveDataWifi } = require('../../utils/storage/utilstorage');

exports.tmpdir = osName === 'windows' ? `${process.env.WINDIR}\\Temp` : '/tmp';

const config = require('../../../utils/configfile');
Expand All @@ -42,6 +44,7 @@ let ROTATED_PATH;
let WINSVC_LOG;
let WINSVC_UPDATER;
let LOGS_ZIP_PATH;
let wifiDataPath;

const collectFiles = (outputFile, cb) => {
const output = fs.createWriteStream(outputFile);
Expand All @@ -61,6 +64,7 @@ const collectFiles = (outputFile, cb) => {
const files = [
{ path: CONF_PATH, name: 'prey.conf' },
{ path: LOG_PATH, name: 'prey.log' },
{ path: wifiDataPath, name: 'wifi_data.json' },
{ path: COMMANDS_PATH, name: 'commands.db' },
{ path: ROTATED_PATH, name: 'prey.log.1.gz' },
...(os.platform() === 'win32' ? [ // Only for windows add admin service logs
Expand Down Expand Up @@ -156,16 +160,28 @@ exports.start = (id, options, cb) => {
WINSVC_LOG = join(CONFIG_PATH, 'winsvc.log');
WINSVC_UPDATER = join(CONFIG_PATH, 'updater.log');
LOGS_ZIP_PATH = join(exports.tmpdir, 'logs.zip');
wifiDataPath = join(exports.tmpdir, 'wifi_data.json');

// eslint-disable-next-line consistent-return
collectFiles(LOGS_ZIP_PATH, (err, bytes) => {
if (err) return done(id, err);
retrieveDataWifi((txt) => {
let jsonInformation = ' ';
if (txt !== '') {
const txtParsed = JSON.parse(txt);
jsonInformation = JSON.stringify(txtParsed, null, 2);
}
// eslint-disable-next-line consistent-return
fs.writeFile(wifiDataPath, jsonInformation, { flag: 'w+' }, (error) => {
if (error) return done(id, error);
// eslint-disable-next-line consistent-return
collectFiles(LOGS_ZIP_PATH, (err, bytes) => {
if (err) return done(id, err);

exports.upload_zip(LOGS_ZIP_PATH, bytes, (errUpload) => done(id, errUpload));
});
exports.upload_zip(LOGS_ZIP_PATH, bytes, (errUpload) => done(id, errUpload));
});

em = em || new Emitter();
if (cb) cb(null, em);
em = em || new Emitter();
if (cb) cb(null, em);
});
});
};

exports.stop = () => {
Expand Down
42 changes: 20 additions & 22 deletions lib/agent/control-panel/api/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,47 +10,42 @@ const defaults = {
protocol: config.getData('control-panel.protocol'),
host: config.getData('control-panel.host'),
user_agent: common.system.user_agent,
// timeout should be longer than notification server's timeout which is 60 seconds
// to avoid errors when notify takes a little longer than 60 seconds for cutting the connection
timeout: 120 * 1000,
retry_timeout: 3 * 1000,
try_proxy: '',
};

// TODO: refactor this file

https.globalAgent.options.secureProtocol = 'TLSv1_2_method';

const api_root = '/api/v2';
const max_attempts = 3;

const is_network_down = function (err) {
const is_network_down = (err) => {
const codes = ['ENETDOWN', 'ENETUNREACH', 'EADDRINFO', 'ENOTFOUND', 'EHOSTUNREACH'];
return codes.indexOf(err.code) !== -1;
};

const is_server_down = function (err) {
const is_server_down = (err) => {
const codes = ['ETIMEDOUT', 'ECONNRESET', 'ECONNREFUSED'];
return codes.indexOf(err.code) !== -1;
};

const is_temporary_error = function (err, resp) {
const is_temporary_error = (err, resp) => {
let retry = false;

if (err) { retry = (is_server_down(err) || err.message.match('socket hang up')); } else { retry = (resp.statusCode == 502 || resp.statusCode == 503); }

return retry;
};

const send = function (attempt, method, path, data, options, cb) {
exports.send = (attempt, method, path, data, options, cb) => {
if (!defaults.client) {
const err = new Error('No HTTP client set!');
if (cb) return cb(err);
return err;
}

// opts are used for the current request, while options are
// used in the recursive call in case of retry
const opts = options || {};
opts.timeout = opts.timeout || defaults.timeout;
opts.user_agent = opts.user_agent || defaults.user_agent;
Expand All @@ -75,10 +70,10 @@ const send = function (attempt, method, path, data, options, cb) {
if (cb) {
defaults.client.request(method, url, data, opts, (err, resp, body) => {
const seconds = (new Date() - start) / 1000;
const retry_without_proxy = function () {
const retry_without_proxy = () => {
delete options.proxy;
logger.debug('Retrying request without proxy.');
send(1, method, path, data, options, cb);
exports.send(1, method, path, data, options, cb);
};
logger.debug(`Attempt #${attempt} took ${seconds} seconds.`);

Expand All @@ -88,15 +83,18 @@ const send = function (attempt, method, path, data, options, cb) {
return retry_without_proxy();
}
return cb(err);
} if (is_temporary_error(err, resp)) {
if (attempt < max_attempts) { // retry the request
}
if (is_temporary_error(err, resp)) {
if (attempt < max_attempts) {
logger.debug('Temporary network error. Retrying...');
return setTimeout(() => {
send(attempt + 1, method, path, data, options, cb);
exports.send(attempt + 1, method, path, data, options, cb);
}, defaults.retry_timeout);
} if (opts.proxy) {
}
if (opts.proxy) {
return retry_without_proxy();
} if (err) { // maxed out all attempts. tell user to retry in a sec.
}
if (err) {
err.message += ' - Please try again in a minute.';
}
}
Expand All @@ -108,33 +106,33 @@ const send = function (attempt, method, path, data, options, cb) {
}
};

const set_proxy_and_send = function (method, path, data, opts, cb) {
const set_proxy_and_send = (method, path, data, opts, cb) => {
if (opts && typeof (opts) === 'object' && !opts.hasOwnProperty('proxy') && defaults.try_proxy) {
opts.proxy = defaults.try_proxy;
logger.debug(`Setting proxy to ${opts.proxy}`);
}
const res = send(1, method, path, data, opts, cb);
const res = exports.send(1, method, path, data, opts, cb);
if (!cb) {
return res;
}
};

exports.get = function (path, opts, cb) {
exports.get = (path, opts, cb) => {
const res = set_proxy_and_send('GET', path, null, opts, cb);
if (!cb) {
return res;
}
};

exports.post = function (path, data, opts, cb) {
exports.post = (path, data, opts, cb) => {
set_proxy_and_send('POST', path, data, opts, cb);
};

exports.delete = function (path, opts, cb) {
exports.delete = (path, opts, cb) => {
set_proxy_and_send('DELETE', path, null, opts, cb);
};

exports.use = function (obj) {
exports.use = (obj) => {
for (const key in obj) {
if (defaults.hasOwnProperty(key)) {
if (key == 'protocol' && ['http', 'https'].indexOf(obj[key]) === -1) {
Expand Down
Loading

0 comments on commit 6355197

Please sign in to comment.