diff --git a/README.md b/README.md index 31c0ce0f..32170535 100644 --- a/README.md +++ b/README.md @@ -31,9 +31,9 @@ Components Control. Can be configured to do one o more things (or nothing) | Variable Name | Usage | | ----- | ----- | | COMMANDER_DISABLED | disable internal commander api | -| MONITORING_DISABLED | disable monitoring system. system monitors will not be checked anymore. will only change when bots and agents send updates | +| MONITORING_DISABLED | disable monitoring system. The core will stop checking monitors status. Events for monitor status will be triggered on API updates | | API_DISABLED | disable rest api | -| SCHEDULER_JOBS_DISABLED | disable internal scheduler execution. scheduler-jobs will be created using the rest api but task will never be executed. theeye-jobs execution timeout will be never checked. | +| SCHEDULER_JOBS_DISABLED | disable internal scheduler execution. scheduled jobs can be created but jobs will not be created. | ### Start development sample diff --git a/config/default.js b/config/default.js index 30b1140a..189c85d4 100644 --- a/config/default.js +++ b/config/default.js @@ -13,6 +13,7 @@ module.exports = { file_upload_folder: join(__dirname , '..', 'uploads'), view_teamplates_path: __dirname + '/../core/view/template', secret: 'b28d9f2a4d52ace6e5d3ac1dd3e5c2a0e7e66472ec7276ca501b8c4fa1f07679', + secret_uuid: 'a2a29a19-aba1-412b-a9ba-c29668e3c17b', user: { username: 'theeye-automatic', email: 'info@theeye.io', diff --git a/core/app/api.js b/core/app/api.js index d22ee5ea..754e299c 100644 --- a/core/app/api.js +++ b/core/app/api.js @@ -56,17 +56,17 @@ module.exports = function () { // respond with error middleware server.use((req, res, next) => { - res.sendError = (error, next) => { - if (error.statusCode < 500) { - res.send(error.statusCode || 400, { - statusCode: error.statusCode, - message: error.message, - errors: error.errors + res.sendError = (err, next) => { + if (err instanceof ErrorHandler.ClientError || err.statusCode < 500) { + res.send(err.statusCode || 400, { + statusCode: err.statusCode, + message: err.message, + errors: err.errors }) } else { - logger.error(error) + logger.error(err) const handler = new ErrorHandler() - handler.sendExceptionAlert(error, req) + handler.sendExceptionAlert(err, req) res.send(500, 'Internal Server Error') } if (next) { next() } diff --git a/core/constants/indicator.js b/core/constants/indicator.js index d11a95e1..8c8555c9 100644 --- a/core/constants/indicator.js +++ b/core/constants/indicator.js @@ -1,10 +1,12 @@ -const SHORT_TYPE_CHART = 'chart' -const SHORT_TYPE_TEXT = 'text' +const SHORT_TYPE_CHART = 'chart' +const SHORT_TYPE_TEXT = 'text' const SHORT_TYPE_PROGRESS = 'progress' -const SHORT_TYPE_COUNTER = 'counter' +const SHORT_TYPE_COUNTER = 'counter' +const SHORT_TYPE_FILE = 'file' -exports.SHORT_TYPE_CHART = SHORT_TYPE_CHART +exports.SHORT_TYPE_CHART = SHORT_TYPE_CHART exports.SHORT_TYPE_TEXT = SHORT_TYPE_TEXT exports.SHORT_TYPE_PROGRESS = SHORT_TYPE_PROGRESS exports.SHORT_TYPE_COUNTER = SHORT_TYPE_COUNTER +exports.SHORT_TYPE_FILE = SHORT_TYPE_FILE \ No newline at end of file diff --git a/core/controllers/file.js b/core/controllers/file.js index 7d35c6d2..c5cc53f9 100644 --- a/core/controllers/file.js +++ b/core/controllers/file.js @@ -22,25 +22,29 @@ module.exports = (server) => { } }) - const middlewares = [ - server.auth.bearerMiddleware, - router.resolve.customerNameToEntity({ required: true }), - router.ensureCustomer - ] - // FETCH - server.get('/:customer/file', middlewares, fetchFiles) + server.get('/:customer/file', + server.auth.bearerMiddleware, + router.resolve.customerSessionToEntity(), + router.ensureCustomer, + fetchFiles + ) // GET server.get('/:customer/file/:file', - middlewares, + server.auth.bearerMiddleware, + router.resolve.customerSessionToEntity(), + router.ensureCustomer, router.resolve.idToEntity({ param: 'file', required: true }), getFile ) // CREATE server.post('/:customer/file', - middlewares.concat(router.requireCredential('admin')), + server.auth.bearerMiddleware, + router.resolve.customerSessionToEntity(), + router.ensureCustomer, + router.requireCredential('admin'), upload.single('file'), createFile, audit.afterCreate('file', { display: 'filename' }) @@ -48,7 +52,9 @@ module.exports = (server) => { // UPDATE server.put('/:customer/file/:file', - middlewares, + server.auth.bearerMiddleware, + router.resolve.customerSessionToEntity(), + router.ensureCustomer, router.requireCredential('admin'), router.resolve.idToEntity({ param:'file', required:true }), upload.single('file'), @@ -59,7 +65,9 @@ module.exports = (server) => { // DELETE server.del('/:customer/file/:file', - middlewares, + server.auth.bearerMiddleware, + router.resolve.customerSessionToEntity(), + router.ensureCustomer, router.requireCredential('admin'), router.resolve.idToEntity({ param: 'file', required: true }), removeFile, @@ -70,7 +78,7 @@ module.exports = (server) => { server.get('/:customer/file/:file/download', server.auth.bearerMiddleware, router.requireCredential('user'), - router.resolve.customerNameToEntity({required:true}), + router.resolve.customerSessionToEntity(), router.ensureCustomer, router.resolve.idToEntity({param:'file',required:true}), downloadFile @@ -78,7 +86,9 @@ module.exports = (server) => { // GET LINKED MODELS server.get('/:customer/file/:file/linkedmodels', - middlewares, + server.auth.bearerMiddleware, + router.resolve.customerSessionToEntity(), + router.ensureCustomer, router.resolve.idToEntity({ param:'file', required:true }), getLinkedModels ) diff --git a/core/controllers/host.js b/core/controllers/host.js index 4b4df826..37c89830 100644 --- a/core/controllers/host.js +++ b/core/controllers/host.js @@ -1,7 +1,7 @@ -'use strict' -const App = require('../app') +const restify = require('restify') const config = require('config') +const App = require('../app') const Constants = require('../constants') const dbFilter = require('../lib/db-filter') const Host = require("../entity/host").Entity @@ -11,11 +11,13 @@ const NotificationService = require('../service/notification') const Resource = require('../entity/resource').Entity const router = require('../router') const TopicsConstants = require('../constants/topics') +const machineFingerprint = require('../lib/machine-fingerprint') +const { ClientError, ServerError } = require('../lib/error-handler') module.exports = function (server) { const middlewares = [ server.auth.bearerMiddleware, - router.resolve.customerNameToEntity({ required: true }), + router.resolve.customerSessionToEntity({ required: true }), router.ensureCustomer, ] @@ -27,31 +29,38 @@ module.exports = function (server) { controller.get ) - /** - * NEW ROUTES WITH CUSTOMER , TO KEEP IT GENERIC - */ + server.put('/:customer/host/:host/reconfigure', + middlewares, + router.resolve.idToEntity({ param: 'host', required: true }), + router.requireCredential('admin'), + controller.reconfigure + ) + server.post('/:customer/host/:hostname', middlewares, - router.requireCredential('agent',{exactMatch:true}), // only agents can create hosts + router.requireCredential('agent', { exactMatch: true }), // only agents can create hosts controller.create ) - /** - * KEEP OLD ROUTE FOR BACKWARD COMPATIBILITY WITH OLDER AGENTS - * - * AGENTS VERSION <= v0.9.1 - */ server.post('/host/:hostname', - middlewares, + server.auth.bearerMiddleware, + router.resolve.customerSessionToEntity({ required: true }), + router.ensureCustomer, router.requireCredential('agent', { exactMatch: true }), // only agents can create hosts controller.create ) - server.put('/:customer/host/:host/reconfigure', - middlewares, - router.resolve.idToEntity({ param: 'host', required: true }), - router.requireCredential('admin'), - controller.reconfigure + // + // new agents registration process. + // + server.post('/host', + server.auth.bearerMiddleware, + router.resolve.customerSessionToEntity(), + router.ensureCustomer, + router.requireCredential('agent', { exactMatch: true }), // only agents can create hosts + restify.plugins.conditionalHandler([ + { version: '1.2.4', handler: controller.register } + ]) ) } @@ -102,6 +111,22 @@ const controller = { }) }) }, + async register (req, res, next) { + try { + const { user, customer, body } = req + const hostname = (req.params.hostname || req.body.hostname) + const data = await registerPullAgent({ user, customer, hostname, info: body.info }) + + const payload = Object.assign({}, config.agent.core_workers.host_ping) + payload.host_id = data.host._id + payload.resource_id = data.resource._id + payload.connection_id = data.connection.fingerprint + + res.send(200, payload) + } catch (err) { + res.sendError(err) + } + }, /** * * @@ -114,7 +139,7 @@ const controller = { logger.log('processing hostname "%s" registration request', hostname) - registerHostname(req, (error, result) => { + registerAgent(req, (error, result) => { if (error) { logger.error(error) return res.send() @@ -150,13 +175,14 @@ const controller = { * @param {Function} done callback * @return null */ -const registerHostname = (req, done) => { +const registerAgent = (req, done) => { const customer = req.customer - const hostname = req.params.hostname + const hostname = (req.params.hostname || req.body.hostname) + const body = req.body // setting up registration properties - const properties = req.body.info || {} - properties.agent_version = req.body.version || null + const properties = body.info || {} + properties.agent_version = body.version || null Host.findOne({ hostname, @@ -210,26 +236,24 @@ const registerHostname = (req, done) => { } /** update agent reported version **/ - function updateAgentVersion () { - logger.log('updating agent version') - host.agent_version = properties.agent_version - host.last_update = new Date() - host.save(err => { - if (err) { - logger.error(err) - return - } - - const topic = TopicsConstants.agent.version - App.logger.submit(customer.name, topic, { - hostname, - organization: customer.name, - version: host.agent_version - }) // topic = topics.agent.version - }) - } - - updateAgentVersion() + //function updateAgentVersion () { + // logger.log('updating agent version') + // host.agent_version = properties.agent_version + // host.last_update = new Date() + // host.save(err => { + // if (err) { + // logger.error(err) + // return + // } + // const topic = TopicsConstants.agent.version + // App.logger.submit(customer.name, topic, { + // hostname, + // organization: customer.name, + // version: host.agent_version + // }) // topic = topics.agent.version + // }) + //} + //updateAgentVersion() Resource.findOne({ host_id: host._id, @@ -251,3 +275,86 @@ const registerHostname = (req, done) => { } }) } + +const registerPullAgent = async (input) => { + const { user, customer, info, hostname } = input + + let resource + let host = await Host.findOne({ + hostname, + customer_name: customer.name + }) + + if (!host) { + const result = await new Promise((resolve, reject) => { + HostService.register({ + user, + hostname, + customer, + info + }, (err, result) => { + if (err) { reject(err) } + else { resolve(result) } + }) + }) + + resource = result.resource + host = result.host + + NotificationService.generateSystemNotification({ + topic: TopicsConstants.host.registered, + data: { + model_type:'Host', + model: host, + model_id: host._id, + hostname, + organization: customer.name, + organization_id: customer._id, + operations: Constants.CREATE + } + }) + + HostService.provision({ + host, + resource, + customer, + user, + skip_auto_provisioning: input.skip_auto_provisioning + }) + } else { + resource = await Resource.findOne({ + host_id: host._id, + type: 'host' + }) + + if (!resource) { + throw new ServerError('Host resource not found') + } + } + + const connection = await registerHostFingerprint(host, info) + + return { host, resource, connection } +} + +const registerHostFingerprint = async (host, info) => { + const calc = machineFingerprint(info) + + const registered = host.fingerprints.find(fp => { + return fp.fingerprint === calc + }) + + if (registered !== undefined) { + return registered + } + + const fingerprint = Object.assign({}, info, { + fingerprint: calc, + creation_date: new Date() + }) + + host.fingerprints.push(fingerprint) + await host.save() + + return fingerprint +} diff --git a/core/controllers/indicator/counter.js b/core/controllers/indicator/counter.js index 7a9fb6f3..6f02ad08 100644 --- a/core/controllers/indicator/counter.js +++ b/core/controllers/indicator/counter.js @@ -6,14 +6,11 @@ const TopicsConstants = require('../../constants/topics') const Constants = require('../../constants') module.exports = function (server) { - var middlewares = [ - server.auth.bearerMiddleware, - router.resolve.customerNameToEntity({ required: true }), - router.ensureCustomer - ] - server.patch( '/indicator/:indicator/increase', - middlewares, + server.patch('/indicator/:indicator/increase', + server.auth.bearerMiddleware, + router.resolve.customerSessionToEntity(), + router.ensureCustomer, router.requireCredential('agent'), router.resolve.idToEntity({ param:'indicator', required: true }), isNumericIndicator, @@ -22,8 +19,22 @@ module.exports = function (server) { notifyEvent({ operation: Constants.UPDATE }) ) - server.patch( '/indicator/:indicator/decrease', - middlewares, + server.patch('/indicator/title/:title/increase', + server.auth.bearerMiddleware, + router.resolve.customerSessionToEntity(), + router.ensureCustomer, + router.requireCredential('agent'), + findByTitleMiddleware(), + isNumericIndicator, + controller.increase, + audit.afterUpdate('indicator', { display: 'title' }), + notifyEvent({ operation: Constants.UPDATE }) + ) + + server.patch('/indicator/:indicator/decrease', + server.auth.bearerMiddleware, + router.resolve.customerSessionToEntity(), + router.ensureCustomer, router.requireCredential('agent'), router.resolve.idToEntity({ param:'indicator', required: true }), isNumericIndicator, @@ -32,8 +43,22 @@ module.exports = function (server) { notifyEvent({ operation: Constants.UPDATE }) ) - server.patch( '/indicator/:indicator/restart', - middlewares, + server.patch('/indicator/title/:title/decrease', + server.auth.bearerMiddleware, + router.resolve.customerSessionToEntity(), + router.ensureCustomer, + router.requireCredential('agent'), + findByTitleMiddleware(), + isNumericIndicator, + controller.decrease, + audit.afterUpdate('indicator', { display: 'title' }), + notifyEvent({ operation: Constants.UPDATE }) + ) + + server.patch('/indicator/:indicator/restart', + server.auth.bearerMiddleware, + router.resolve.customerSessionToEntity(), + router.ensureCustomer, router.requireCredential('agent'), router.resolve.idToEntity({ param:'indicator', required: true }), isNumericIndicator, @@ -41,6 +66,42 @@ module.exports = function (server) { audit.afterUpdate('indicator', { display: 'title' }), notifyEvent({ operation: Constants.UPDATE }) ) + + server.patch('/indicator/title/:title/restart', + server.auth.bearerMiddleware, + router.resolve.customerSessionToEntity(), + router.ensureCustomer, + router.requireCredential('agent'), + findByTitleMiddleware(), + isNumericIndicator, + controller.restart, + audit.afterUpdate('indicator', { display: 'title' }), + notifyEvent({ operation: Constants.UPDATE }) + ) +} + +const findByTitleMiddleware = (options = {}) => { + return (req, res, next) => { + const title = req.params.title + const customer = req.customer + + App.Models.Indicator.Indicator.findOne({ + title, + customer_id: customer._id + }, (err, indicator) => { + if (err) { + logger.error(err) + return res.send(500, err.message) + } + + if (!indicator && options.required !== false) { + return res.send(404, 'indicator not found') + } + + req.indicator = indicator + return next() + }) + } } const controller = { diff --git a/core/controllers/scheduler/index.js b/core/controllers/scheduler/index.js index 80b7b466..32fd7d73 100644 --- a/core/controllers/scheduler/index.js +++ b/core/controllers/scheduler/index.js @@ -59,7 +59,7 @@ module.exports = (server) => { server.del('/scheduler/:schedule', server.auth.bearerMiddleware, Router.requireCredential('admin'), - Router.resolve.customerSessionToEntity({ required: true }), + Router.resolve.customerSessionToEntity(), Router.ensureCustomer, schedulerResolver, remove, @@ -70,7 +70,7 @@ module.exports = (server) => { server.put('/scheduler/:schedule/stop', server.auth.bearerMiddleware, Router.requireCredential('admin'), - Router.resolve.customerSessionToEntity({ required: true }), + Router.resolve.customerSessionToEntity(), Router.ensureCustomer, schedulerResolver, stop, @@ -81,7 +81,7 @@ module.exports = (server) => { server.put('/scheduler/:schedule/start', server.auth.bearerMiddleware, Router.requireCredential('admin'), - Router.resolve.customerSessionToEntity({ required: true }), + Router.resolve.customerSessionToEntity(), Router.ensureCustomer, schedulerResolver, start, diff --git a/core/controllers/task/crud.js b/core/controllers/task/crud.js index ffbceb59..6523fcea 100644 --- a/core/controllers/task/crud.js +++ b/core/controllers/task/crud.js @@ -11,59 +11,65 @@ const TaskConstants = require('../../constants/task') module.exports = (server) => { server.get('/:customer/task', [ server.auth.bearerMiddleware, - router.resolve.customerNameToEntity({ required: true }), + router.resolve.customerSessionToEntity(), router.ensureCustomer, router.requireCredential('viewer'), - router.resolve.idToEntity({ param: 'host', required: false }) + router.resolve.idToEntityByCustomer({ param: 'host', required: false }) ], controller.fetch) server.get('/:customer/task/:task', [ server.auth.bearerMiddleware, - router.resolve.customerNameToEntity({ required: true }), + router.resolve.customerSessionToEntity(), router.ensureCustomer, router.requireCredential('viewer'), - router.resolve.idToEntity({ param: 'task', required: true }), + router.resolve.idToEntityByCustomer({ param: 'task', required: true }), router.ensureAllowed({ entity: { name: 'task' } }) ], controller.get) - const middlewares = [ + server.post('/:customer/task', server.auth.bearerMiddleware, - router.resolve.customerNameToEntity({ required: true }), - router.ensureCustomer - ] - - server.post( - '/:customer/task', - middlewares.concat([ - router.requireCredential('admin'), - router.resolve.idToEntity({ param: 'script', entity: 'file' }), - router.resolve.idToEntity({ param: 'host' }) - ]), + router.resolve.customerSessionToEntity(), + router.ensureCustomer, + router.requireCredential('admin'), + router.resolve.idToEntityByCustomer({ param: 'script', entity: 'file' }), + router.resolve.idToEntityByCustomer({ param: 'host' }), controller.create, audit.afterCreate('task', { display: 'name' }) ) - const mws = middlewares.concat( - router.requireCredential('admin'), - router.resolve.idToEntity({ param: 'task', required: true }), - router.resolve.idToEntity({ param: 'host_id', entity: 'host', into: 'host' }) - ) - server.patch('/:customer/task/:task', - mws, + server.auth.bearerMiddleware, + router.resolve.customerSessionToEntity(), + router.ensureCustomer, + router.requireCredential('admin'), + router.resolve.idToEntityByCustomer({ param: 'script', entity: 'file' }), + router.resolve.idToEntityByCustomer({ param: 'host' }), + router.resolve.idToEntityByCustomer({ param: 'task', required: true }), + router.resolve.idToEntityByCustomer({ param: 'host_id', entity: 'host', into: 'host' }), controller.replace, audit.afterUpdate('task', { display: 'name' }) ) server.put('/:customer/task/:task', - mws, - router.resolve.idToEntity({ param: 'script', entity: 'file' }), + server.auth.bearerMiddleware, + router.resolve.customerSessionToEntity(), + router.ensureCustomer, + router.requireCredential('admin'), + router.resolve.idToEntityByCustomer({ param: 'script', entity: 'file' }), + router.resolve.idToEntityByCustomer({ param: 'host' }), + router.resolve.idToEntityByCustomer({ param: 'task', required: true }), + router.resolve.idToEntityByCustomer({ param: 'host_id', entity: 'host', into: 'host' }), + router.resolve.idToEntityByCustomer({ param: 'script', entity: 'file' }), controller.replace, audit.afterReplace('task', { display: 'name' }) ) server.del('/:customer/task/:task', - mws, + server.auth.bearerMiddleware, + router.resolve.customerSessionToEntity(), + router.ensureCustomer, + router.requireCredential('admin'), + router.resolve.idToEntityByCustomer({ param: 'task', required: true }), controller.remove, audit.afterRemove('task', { display: 'name' }) ) diff --git a/core/controllers/task/job.js b/core/controllers/task/job.js index 886ac38e..671fc56d 100644 --- a/core/controllers/task/job.js +++ b/core/controllers/task/job.js @@ -40,6 +40,18 @@ module.exports = (server) => { createJob ) + // + // new version + // + server.post('/task/:task/job', + server.auth.bearerMiddleware, + router.resolve.customerSessionToEntity(), + router.requireCredential('user'), + router.resolve.idToEntityByCustomer({ param: 'task', required: true }), + router.ensureAllowed({ entity: { name: 'task' } }), + createJob + ) + server.post('/:customer/task/:task/secret/:secret/job', router.resolve.idToEntity({ param: 'task', required: true }), router.requireSecret('task'), diff --git a/core/controllers/workflow/crud.js b/core/controllers/workflow/crud.js index eda733e7..4e5b9f75 100644 --- a/core/controllers/workflow/crud.js +++ b/core/controllers/workflow/crud.js @@ -1,213 +1,109 @@ +const restify = require('restify') const graphlib = require('graphlib') const App = require('../../app') const TopicsConstants = require('../../constants/topics') const logger = require('../../lib/logger')('controller:workflow') +const audit = require('../../lib/audit') const router = require('../../router') // const audit = require('../../lib/audit') -const Workflow = require('../../entity/workflow').Workflow -const Task = require('../../entity/task').Entity -const Tag = require('../../entity/tag').Entity const ACL = require('../../lib/acl'); const dbFilter = require('../../lib/db-filter'); +const crudv2 = require('./crudv2') + module.exports = function (server) { - // const crudTopic = TopicsConstants.workflow.crud + const CRUD_TOPIC = TopicsConstants.workflow.crud - // default middlewares - var middlewares = [ + server.get('/workflows', server.auth.bearerMiddleware, - router.resolve.customerNameToEntity({required: true}), - router.ensureCustomer - ] - - server.get( - '/workflows', - middlewares, - router.requireCredential('viewer') , - controller.fetch + router.resolve.customerSessionToEntity(), + router.ensureCustomer, + router.requireCredential('viewer'), + fetch ) - server.get( - '/workflows/:workflow', - middlewares, + server.get('/workflows/:workflow', + server.auth.bearerMiddleware, + router.resolve.customerSessionToEntity(), + router.ensureCustomer, router.requireCredential('viewer'), router.resolve.idToEntity({ param: 'workflow', required: true }), router.ensureAllowed({ entity: { name: 'workflow' } }) , - controller.get + (req, res, next) => { + res.send(200, req.workflow) + next() + } ) - server.post( - '/workflows', - middlewares, - router.requireCredential('admin') , - controller.create - // audit.afterCreate('workflow',{ display: 'name' }) // cannot audit bulk creation + server.post('/workflows', + server.auth.bearerMiddleware, + router.resolve.customerSessionToEntity(), + router.ensureCustomer, + router.requireCredential('admin'), + restify.plugins.conditionalHandler([ + { version: '2.9.0', handler: crudv2.create } + ]), + audit.afterCreate('workflow', { display: 'name', topic: CRUD_TOPIC }) ) - server.del( - '/workflows/:workflow', - middlewares, + server.del('/workflows/:workflow', + server.auth.bearerMiddleware, + router.resolve.customerSessionToEntity(), + router.ensureCustomer, router.requireCredential('admin'), - router.resolve.idToEntity({param: 'workflow', required: true}) , - controller.remove - // audit.afterRemove('workflow',{ display: 'name', topic: crudTopic }) + router.resolve.idToEntity({param: 'workflow', required: true}), + restify.plugins.conditionalHandler([ + { version: '1.0.0', handler: remove }, + { version: '2.9.0', handler: crudv2.remove } + ]), + audit.afterRemove('workflow', { display: 'name', topic: CRUD_TOPIC }) ) - server.put( - '/workflows/:workflow', - middlewares, + server.put('/workflows/:workflow', + server.auth.bearerMiddleware, + router.resolve.customerSessionToEntity(), + router.ensureCustomer, router.requireCredential('admin'), - router.resolve.idToEntity({param: 'workflow', required: true}) , - controller.replace - // audit.afterReplace('workflow',{ display: 'name', topic: crudTopic }) + router.resolve.idToEntity({ param: 'workflow', required: true }) , + restify.plugins.conditionalHandler([ + { version: '2.9.0', handler: crudv2.replace } + ]), + audit.afterReplace('workflow', { display: 'name', topic: CRUD_TOPIC }) ) } -const controller = { - /** - * - * @method GET - * - */ - get (req, res, next) { - res.send(200, req.workflow) - next() - }, - /** - * - * @method GET - * - */ - fetch (req, res, next) { - const customer = req.customer - const input = req.query - - const filter = dbFilter(input,{ /** default **/ }) - filter.where.customer_id = customer.id - if (!ACL.hasAccessLevel(req.user.credential,'admin')) { - // find what this user can access - filter.where.acl = req.user.email - } - - Workflow.fetchBy(filter, (err, workflows) => { - if (err) return res.send(500, err) - res.send(200, workflows) - next() - }) - }, - /** - * - * @method DELETE - * - */ - remove (req, res, next) { - var workflow = req.workflow - workflow.remove(err => { - if (err) return res.send(500,err) - - unlinkWorkflowTasks(req) - res.send(200) - }) - }, - /** - * - * @method PUT - * - */ - replace (req, res, next) { - replaceWorkflow(req, (err, workflow) => { - if (err) { - return res.send(err.statusCode || 500, err) - } - - assignWorkflowAclToTasks(workflow, (err) => { - if (err) { return res.send(err.statusCode || 500, err) } - - res.send(200, workflow) - }) - }) - }, - //async acl (req, res, next) { - // try { - // const workflow = req.workflow - // // validate acl - // workflow.acl = req.body - // assignWorkflowAclToTasks(workflow, (err) => { - // if (err) { - // return res.send(err.statusCode || 500, err) - // } - // res.send(200, workflow) - // }) - // } catch (err) { - // } - //}, - /** - * - * @method POST - * - */ - create (req, res, next) { - createWorkflow(req, (err, workflow) => { - if (err) { return res.send(err.statusCode || 500, err) } - - assignTasksToWorkflow(req, (err) => { - if (err) { return res.send(err.statusCode || 500, err) } - - return res.send(200, workflow) - }) - }) +/** + * + * @method GET + * + */ +const fetch = (req, res, next) => { + const { customer, input = {} } = req + + const filter = dbFilter(input, { /** default **/ }) + filter.where.customer_id = customer.id + if (!ACL.hasAccessLevel(req.user.credential,'admin')) { + // find what this user can access + filter.where.acl = req.user.email } -} - -const createWorkflow = (req, next) => { - const customer = req.customer - const body = req.body - const graph = graphlib.json.read(body.graph) - - validateGraph(graph, (err) => { - if (err) { - err.statusCode = 400 - return next(err) - } - var workflow = new Workflow( - Object.assign({}, body, { - _type: 'Workflow', - customer: customer.id, - customer_id: customer.id, - user: req.user.id, - user_id: req.user.id - }) - ) - - workflow.save(err => { - if (err) { logger.error('%o', err) } - req.workflow = workflow - createTags(body.tags, customer) - return next(err, workflow) - }) + App.Models.Workflow.Workflow.fetchBy(filter, (err, workflows) => { + if (err) return res.send(500, err) + res.send(200, workflows) + next() }) } -/** - * - * take all the tasks on this workflow and assign to it - * - */ -const assignTasksToWorkflow = (req, next) => { +const remove = (req, res, next) => { const workflow = req.workflow - const graph = graphlib.json.read(workflow.graph) + workflow.remove(err => { + if (err) return res.send(500,err) - graph.nodes().forEach(id => { - let node = graph.node(id) - if (!/Event/.test(node._type)) { - App.task.assignTaskToWorkflow(id, workflow) - } + unlinkWorkflowTasks(req) + res.send(200) }) - - next() } const unlinkWorkflowTasks = (req) => { @@ -219,80 +115,3 @@ const unlinkWorkflowTasks = (req) => { } }) } - -const replaceWorkflow = (req, next) => { - const workflow = req.workflow - const body = req.body - const newgraph = graphlib.json.read(body.graph) - const oldgraph = graphlib.json.read(workflow.graph) - - validateGraph(newgraph, (err) => { - if (err) { - err.statusCode = 400 - return next(err) - } - - workflow.set(body) - workflow.save(err => { - if (err) { - logger.error('%s, %s, errors: %o',err.name, err.message, err.errors) - if (err.name === 'ValidationError') { - err.statusCode = 400 - } - return next(err) - } - - updateWorkflowGraphTasksDiferences(oldgraph, newgraph, workflow) - createTags(body.tags, req.customer) - - next(err, workflow) - }) - }) -} - -const createTags = (tags, customer) => { - if (tags && Array.isArray(tags)) { - Tag.create(tags, customer) - } -} - -const validateGraph = (graph, next) => { - if (graph.nodes().length === 0 || graph.edges().length === 0) { - return next(new Error('invalid graph definition')) - } - return next() -} - -const updateWorkflowGraphTasksDiferences = (oldgraph, newgraph, workflow) => { - newgraph.nodes().forEach(id => { - let node = oldgraph.node(id) - if (!node) { // is new - node = newgraph.node(id) - if (!/Event/.test(node._type)) { - App.task.assignTaskToWorkflow(id, workflow) - } - } - }) - oldgraph.nodes().forEach(id => { - let node = newgraph.node(id) - if (!node) { // is no more in the workflow - node = oldgraph.node(id) - if (!/Event/.test(node._type)) { - App.task.unlinkTaskFromWorkflow(id) - } - } - }) -} - -const assignWorkflowAclToTasks = (workflow, next) => { - const graph = graphlib.json.read(workflow.graph) - - graph.nodes().forEach(id => { - let node = graph.node(id) - if (!/Event/.test(node._type)) { - App.task.assignWorkflowAclToTask(id, workflow) - } - }) - - next() -} diff --git a/core/controllers/workflow/crudv2.js b/core/controllers/workflow/crudv2.js new file mode 100644 index 00000000..032c2704 --- /dev/null +++ b/core/controllers/workflow/crudv2.js @@ -0,0 +1,287 @@ + +const ObjectId = require('mongoose').Types.ObjectId +const isMongoId = require('validator/lib/isMongoId') +const graphlib = require('graphlib') +const App = require('../../app') +//const logger = require('../../lib/logger')('controller:workflow:crudv2') +const AsyncController = require('../../lib/async-controller') +const { ClientError, ServerError } = require('../../lib/error-handler') +//const formidable = require('formidable') +//const form = formidable({ multiples: true }) + +module.exports = { + /** + * + * @method POST + * + */ + create: AsyncController(async (req, res, next) => { + const { customer, user, body } = req + + //const { fields, files } = await new Promise((resolve, reject) => { + // form.parse(req, (err, fields, files) => { + // if (err) { reject(err) } + // else { resolve({ fields, files }) } + // }) + //}) + + if (body.graph.nodes.length === 0) { + throw new ClientError('invalid graph definition') + } + + const workflow = new App.Models.Workflow.Workflow( + Object.assign({}, body, { + _type: 'Workflow', + customer: customer.id, + customer_id: customer.id, + user: user.id, + user_id: user.id, + version: 2 + }) + ) + + const payload = { workflow, customer, user, body } + const { tasks, graph } = await createTasks(payload) + + // updated grph with created tasks ids + workflow.graph = graph + await workflow.save() + + //createTags(req) + req.workflow = workflow + return workflow + }), + /** + * + * @method DELETE + * + */ + remove: AsyncController(async (req) => { + const { workflow, body } = req + + await Promise.all([ + workflow.remove(), + App.Models.Job.Workflow.deleteMany({ workflow_id: workflow._id.toString() }), + App.scheduler.unscheduleWorkflow(workflow), + removeWorkflowTasks(workflow, body?.keepTasks) + ]) + + return + }), + /** + * + * @method PUT + * + */ + replace: AsyncController(async (req, res, next) => { + const { workflow, customer, user, body } = req + const { graph, tasks, start_task_id } = req.body + + if (body.graph.nodes.length === 0) { + throw new ClientError('invalid graph definition') + } + + const oldgraphlib = graphlib.json.read(workflow.graph) + + const checkRemovedNodes = async () => { + const newgraph = graphlib.json.read(graph) + // update removed nodes + const oldNodes = oldgraphlib.nodes() + for (let id of oldNodes) { + const node = newgraph.node(id) + if (!node) { // it is not in the workflow no more + const oldNode = oldgraphlib.node(id) + if (workflow.version === 2) { + await App.task.destroy(oldNode.id) + } else { + await App.task.unlinkTaskFromWorkflow(oldNode.id) + } + } + } + } + + const checkCreatedNodes = async (graph) => { + // add new nodes + for (let node of graph.nodes) { + if (!oldgraphlib.node(node.v)) { // is not in the workflow + + const props = tasks.find(task => { + return (task.id === node.value.id) + }) + + const model = await App.task.factory( + Object.assign({}, props, { + customer_id: customer._id, + customer: customer, + user: user, + user_id: user.id, + workflow_id: workflow._id, + workflow: workflow, + id: undefined + }) + ) + + if (props.id === start_task_id) { + workflow.start_task = model._id + workflow.start_task_id = model._id + } + + // update node and edges + const newid = model._id.toString() + + // first: update the edges. + for (let edge of graph.edges) { + const eventName = edge.value + + if (edge.v === node.v) { + edge.v = newid + + await createTaskEvent({ + customer_id: customer._id, + name: eventName, + task_id: model._id + }) + } + + if (edge.w === node.v) { + edge.w = newid + + if (isMongoId(edge.v)) { + const task_id = ObjectId(edge.v) + await createTaskEvent({ + customer_id: customer._id, + name: eventName, + task_id + }) + } + } + } + + // second: update the node. + node.value.id = node.v = newid + } + } + } + + await checkRemovedNodes() + await checkCreatedNodes(graph) + + workflow.set(body) + await workflow.save() + + createTags(req) + return workflow + }) +} + +const createTags = ({ body, customer }) => { + const tags = body.tags + if (tags && Array.isArray(tags)) { + App.Models.Tag.Tag.create(tags, customer) + } +} + +const validateGraph = (graph, next) => { + if (graph.nodes().length === 0) { + return next(new Error('invalid graph definition')) + } + return next() +} + +const createTasks = async ({ workflow, customer, user, body }) => { + const { tasks, graph } = body + const models = [] + + for (let node of graph.nodes) { + const props = tasks.find(task => task.id === node.value.id) + const model = await App.task.factory( + Object.assign({}, props, { + customer_id: customer._id, + customer: customer, + user: user, + user_id: user.id, + workflow_id: workflow._id, + workflow: workflow, + id: undefined + }) + ) + + if (props.id === body.start_task_id) { + workflow.start_task = model._id + workflow.start_task_id = model._id + } + + // update node and edges + const id = model._id.toString() + + // first: update the edges. + for (let edge of graph.edges) { + const eventName = edge.value + + if (edge.v === node.v) { + edge.v = id + + await createTaskEvent({ + customer_id: customer._id, + name: eventName, + task_id: model._id + }) + } + + if (edge.w === node.v) { + edge.w = id + + if (isMongoId(edge.v)) { + const task_id = ObjectId(edge.v) + await createTaskEvent({ + customer_id: customer._id, + name: eventName, + task_id + }) + } + } + } + + // second: update the node. + node.value.id = node.v = id + models.push( model ) + } + + return { tasks: models, graph } +} + +const createTaskEvent = async ({ customer_id, name, task_id }) => { + let tEvent = await App.Models.Event.TaskEvent.findOne({ + name, + customer_id, + emitter_id: task_id + }) + if (!tEvent) { + tEvent = new App.Models.Event.TaskEvent({ + name, + customer: customer_id, + customer_id, + emitter: task_id, + emitter_id: task_id + }) + await tEvent.save() + } + return tEvent +} + +const removeWorkflowTasks = (workflow, keepTasks = false) => { + const graph = workflow.graph + const promises = [] + + for (let node of graph.nodes) { + const value = node.value + + if (keepTasks === true) { + promises.push( App.task.unlinkTaskFromWorkflow(value.id) ) + } else { + promises.push( App.task.destroy(value.id) ) + } + } + + return Promise.all(promises) +} diff --git a/core/controllers/workflow/index.js b/core/controllers/workflow/index.js index b93d30d5..c0f41079 100644 --- a/core/controllers/workflow/index.js +++ b/core/controllers/workflow/index.js @@ -5,9 +5,11 @@ const acl = require('./acl') const triggers = require('./triggers') const integrations = require('./integrations') const scheduler = require('./scheduler') +const recipe = require('./recipe') module.exports = (server) => { job(server) + recipe(server) acl(server) crud(server) graph(server) diff --git a/core/controllers/workflow/job.js b/core/controllers/workflow/job.js index c5492ff2..217b3e61 100644 --- a/core/controllers/workflow/job.js +++ b/core/controllers/workflow/job.js @@ -10,11 +10,6 @@ const { ClientError } = require('../../lib/error-handler') const ACL = require('../../lib/acl') module.exports = (server) => { - const middlewares = [ - server.auth.bearerMiddleware, - router.resolve.customerNameToEntity({ required: true }), - router.ensureCustomer - ] const verifyStartingTask = async (req, res, next) => { try { @@ -71,7 +66,9 @@ module.exports = (server) => { ) server.del('/workflows/:workflow/job', - middlewares, + server.auth.bearerMiddleware, + router.resolve.customerNameToEntity({ required: true }), + router.ensureCustomer, router.requireCredential('admin'), router.resolve.idToEntity({ param: 'workflow', required: true }), router.ensureCustomerBelongs('workflow'), diff --git a/core/controllers/workflow/recipe.js b/core/controllers/workflow/recipe.js new file mode 100644 index 00000000..16f43c46 --- /dev/null +++ b/core/controllers/workflow/recipe.js @@ -0,0 +1,67 @@ +const App = require('../../app') +const logger = require('../../lib/logger')('controller:workflow:recipe'); +const router = require('../../router'); + +module.exports = (server) => { + server.get( + '/workflow/:workflow/export', + server.auth.bearerMiddleware, + router.resolve.customerSessionToEntity(), + router.ensureCustomer, + router.requireCredential('admin'), + router.resolve.idToEntity({ param: 'workflow', required: true }), + router.ensureAllowed({ entity: { name: 'workflow' } }), + _export + ) + + server.post( + '/workflow/import', + server.auth.bearerMiddleware, + router.resolve.customerSessionToEntity(), + router.ensureCustomer, + router.requireCredential('admin'), + _import + ) +} + +/** + * @summary export workflow recipe + */ +const _export = async (req, res, next) => { + const workflow = req.workflow + + const graph = workflow.graph + + const expGraph = {} + expGraph.options = graph.options + expGraph.nodes = [] + expGraph.edges = [] + + const exportedTasks = [] + for (let node of graph.nodes) { + const taskId = node.value.id + if (/Event/.test(node.value._type) !== true) { + const task = await App.Models.Task.Task.findById(taskId) + const recipe = await taskRecipe(task) + exportedTasks.push(recipe) + } + } + + return res.send(200, exportedTasks) +} + +const taskRecipe = (task) => { + return new Promise((resolve, reject) => { + App.task.getRecipe(task, (err, data) => { + if (err) reject(err) + else resolve(data) + }) + }) +} + +/** + * @summary import workflow recipe + */ +const _import = (req, res, next) => { + res.send(200) +} diff --git a/core/entity/event/index.js b/core/entity/event/index.js index bc52eba6..04ad8fa2 100644 --- a/core/entity/event/index.js +++ b/core/entity/event/index.js @@ -1,20 +1,19 @@ -'use strict'; -const mongodb = require('../../lib/mongodb').db; +const mongodb = require('../../lib/mongodb').db -var BaseSchema = require('./schema'); -var TaskEventSchema = require('./task'); -var MonitorEventSchema = require('./monitor'); -var WebhookEventSchema = require('./webhook'); +const BaseSchema = require('./schema') +const TaskEventSchema = require('./task') +const MonitorEventSchema = require('./monitor') +const WebhookEventSchema = require('./webhook') // default Event does not have a default Emitter -var Event = mongodb.model('Event', new BaseSchema()); -var TaskEvent = Event.discriminator('TaskEvent', TaskEventSchema); -var MonitorEvent = Event.discriminator('MonitorEvent', MonitorEventSchema); -var WebhookEvent = Event.discriminator('WebhookEvent', WebhookEventSchema); +const Event = mongodb.model('Event', new BaseSchema()) +const TaskEvent = Event.discriminator('TaskEvent', TaskEventSchema) +const MonitorEvent = Event.discriminator('MonitorEvent', MonitorEventSchema) +const WebhookEvent = Event.discriminator('WebhookEvent', WebhookEventSchema) -Event.ensureIndexes(); -exports.Event = Event; -exports.TaskEvent = TaskEvent; -exports.MonitorEvent = MonitorEvent; -exports.WebhookEvent = WebhookEvent; +Event.ensureIndexes() +exports.Event = Event +exports.TaskEvent = TaskEvent +exports.MonitorEvent = MonitorEvent +exports.WebhookEvent = WebhookEvent diff --git a/core/entity/host/schema.js b/core/entity/host/schema.js index 18dd9e34..730b9dbb 100644 --- a/core/entity/host/schema.js +++ b/core/entity/host/schema.js @@ -9,19 +9,9 @@ function HostSchema () { const properties = { disabled: { type: Boolean }, hostname: { type: String, index: true, required: true }, - ip: { type: String }, - os_name: { type: String }, - os_version: { type: String }, - agent_version: { type: String }, customer_name: { type: String, index: true }, customer_id: { type: String }, // Host customer_id is a String , will replace base-schema customer_id - //customer: { type: ObjectId, ref: 'Customer' }, - integrations: { - type: IntegrationsSchema, - default: () => { - return {} - } - } + fingerprints: [ FingerprintSchema ] } // Schema constructor @@ -33,26 +23,47 @@ function HostSchema () { return this } -const NgrokIntegrationSchema = new Schema({ - active: { type: Boolean, default: false }, - url: { type: String, default: '' }, - last_update: { type: Date, default: Date.now }, - last_job: { - type: mongoose.Schema.Types.ObjectId, - ref: 'NgrokIntegrationJob', - default: null - }, - last_job_id: { type: String, default: '' } -},{ _id : false }) - -const IntegrationsSchema = new Schema({ - ngrok: { - type: NgrokIntegrationSchema, - default: () => { - return {} - } +const FingerprintSchema = new Schema({ + creation_date: Date, + fingerprint: String, // calculated data. can be recalculated using information below + platform: String, + hostname: String, + type: String, + release: String, + arch: String, + totalmem: String, + user: String, + cpu: [ Object ], + net: [ Object ], + cwd: String, + agent_version: String, + agent_username: String, + extras: { + user: Object, + agent_pid: String } -},{ _id : false }) +}) + +//const NgrokIntegrationSchema = new Schema({ +// active: { type: Boolean, default: false }, +// url: { type: String, default: '' }, +// last_update: { type: Date, default: Date.now }, +// last_job: { +// type: mongoose.Schema.Types.ObjectId, +// ref: 'NgrokIntegrationJob', +// default: null +// }, +// last_job_id: { type: String, default: '' } +//},{ _id : false }) +// +//const IntegrationsSchema = new Schema({ +// ngrok: { +// type: NgrokIntegrationSchema, +// default: () => { +// return {} +// } +// } +//},{ _id : false }) util.inherits(HostSchema, BaseSchema) diff --git a/core/entity/indicator/index.js b/core/entity/indicator/index.js index 23f55f62..343c5d1f 100644 --- a/core/entity/indicator/index.js +++ b/core/entity/indicator/index.js @@ -28,17 +28,24 @@ const ChartSchema = new BaseSchema({ type: { type: String, default: 'chart' } }) +const FileSchema = new BaseSchema({ + value: { type: String, default: '' }, + type: { type: String, default: 'file' } +}) + const Indicator = mongodb.model('Indicator', IndicatorSchema) const ProgressIndicator = Indicator.discriminator('ProgressIndicator', ProgressSchema) const TextIndicator = Indicator.discriminator('TextIndicator', TextSchema) const CounterIndicator = Indicator.discriminator('CounterIndicator', CounterSchema) const ChartIndicator = Indicator.discriminator('ChartIndicator', ChartSchema) +const FileIndicator = Indicator.discriminator('FileIndicator', FileSchema) Indicator.ensureIndexes() CounterIndicator.ensureIndexes() ProgressIndicator.ensureIndexes() TextIndicator.ensureIndexes() ChartIndicator.ensureIndexes() +FileIndicator.ensureIndexes() // called for both inserts and updates Indicator.on('afterSave', function (model) { @@ -59,6 +66,9 @@ const IndicatorFactory = function (attrs) { if (attrs.type === IndicatorConstants.SHORT_TYPE_COUNTER) { return new CounterIndicator(attrs) } + if (attrs.type === IndicatorConstants.SHORT_TYPE_FILE) { + return new FileIndicator(attrs) + } return new Indicator(attrs) } @@ -68,3 +78,4 @@ exports.Progress = ProgressIndicator exports.Counter = CounterIndicator exports.Text = TextIndicator exports.Chart = ChartIndicator +exports.File = FileIndicator \ No newline at end of file diff --git a/core/entity/workflow/schema.js b/core/entity/workflow/schema.js index 5ed90314..91a282cf 100644 --- a/core/entity/workflow/schema.js +++ b/core/entity/workflow/schema.js @@ -57,6 +57,7 @@ function WorkflowSchema (props) { }, autoremove_completed_jobs: { type: Boolean }, autoremove_completed_jobs_limit: { type: Number, 'default': 5 }, + version: { type: Number } } BaseSchema.call(this, Object.assign({}, properties, props), specs) diff --git a/core/lib/async-controller.js b/core/lib/async-controller.js new file mode 100644 index 00000000..9024e324 --- /dev/null +++ b/core/lib/async-controller.js @@ -0,0 +1,23 @@ +const App = require('../app') +const { ServerError, ClientError } = require('./error-handler') + +module.exports = (fn, options = {}) => { + const controller = async (req, res, next) => { + try { + const result = await fn(req, res) + const body = (result||'ok') + res.send(body) + next() + } catch (err) { + if (err.name === 'ValidationError') { + const clientErr = new ClientError('Invalid Payload') + clientErr.errors = err.errors + res.sendError(clientErr) + } else { + res.sendError(err) + } + } + } + + return controller +} diff --git a/core/lib/async-middleware.js b/core/lib/async-middleware.js new file mode 100644 index 00000000..e327163a --- /dev/null +++ b/core/lib/async-middleware.js @@ -0,0 +1,10 @@ +module.exports = (fn) => { + return async (req, res, next) => { + try { + await fn(req, res) + next() + } catch (err) { + res.sendError(err) + } + } +} diff --git a/core/lib/machine-fingerprint.js b/core/lib/machine-fingerprint.js new file mode 100644 index 00000000..8c3e0c78 --- /dev/null +++ b/core/lib/machine-fingerprint.js @@ -0,0 +1,32 @@ +const config = require('config') +const { v5: uuidv5, v4: uuidv4 } = require('uuid') + +const NAMESPACE = uuidv5(config.system.secret, config.system.secret_uuid) + +module.exports = (machineData) => { + const payload = [] + for (let name in machineData) { + const part = machineData[name] + if (typeof part === 'string') { + payload.push(part) + } else if (name === 'cpu' || name === 'net') { + // an array of available cpu/net + if (Array.isArray(part)) { + for (let idx = 0; idx < part.length; idx++) { + const device = part[idx] + if (name === 'cpu') { + payload.push(device.model) + // array of model, speed + } + else if (name === 'net') { + // array of name, address, mac + payload.push(device.name + device.addres + device.mac) + } + } + } + } + } + payload.sort() + const fingerprint = Buffer.from(payload.join('')).toString('base64') + return uuidv5(fingerprint, NAMESPACE) +} diff --git a/core/service/events/task-trigger-by.js b/core/service/events/task-trigger-by.js index a19a5116..b8416214 100644 --- a/core/service/events/task-trigger-by.js +++ b/core/service/events/task-trigger-by.js @@ -38,6 +38,11 @@ module.exports = async function (payload) { * @param {Job} job the job that generates the event */ const triggeredTaskByEvent = async ({ event, data, job }) => { + + if (!event||!event._id) { + return + } + // search all task triggered by the event, not included in workflows const tasks = await Task.find({ triggers: event._id, diff --git a/core/service/events/workflow.js b/core/service/events/workflow.js index cd4c477a..152d0da0 100644 --- a/core/service/events/workflow.js +++ b/core/service/events/workflow.js @@ -22,7 +22,7 @@ module.exports = async function (payload) { if (payload.job.workflow_job_id) { // a task belonging to a workflow has finished logger.log('This is a workflow event') - await handleWorkflowEvent(payload) + handleWorkflowEvent(payload) } } @@ -33,7 +33,7 @@ module.exports = async function (payload) { payload.topic === TopicConstants.workflow.execution // a task inside a workflow can trigger tasks outside the workflow ) { // workflow trigger has occur - await triggerWorkflowByEvent(payload) + triggerWorkflowByEvent(payload) } } catch (err) { logger.error(err) @@ -50,10 +50,26 @@ const handleWorkflowEvent = async ({ event, data, job }) => { // search workflow step by generated event const workflow = await Workflow.findById(workflow_id) if (!workflow) { return } - await executeWorkflowStep(workflow, workflow_job_id, event, data, job) + + const execution = ( + workflow?.version === 2 ? + executeWorkflowStepVersion2 : + executeWorkflowStep + ) + + return execution(workflow, workflow_job_id, event, data, job) } +/** + * + * @return {Promise} + * + */ const executeWorkflowStep = async (workflow, workflow_job_id, event, argsValues, job) => { + if (!event || !event._id) { + return + } + const graph = new graphlib.json.read(workflow.graph) const nodes = graph.successors(event._id.toString()) // should return tasks nodes if (!nodes) { return } @@ -88,12 +104,67 @@ const executeWorkflowStep = async (workflow, workflow_job_id, event, argsValues, return Promise.all(promises) } +/** + * + * @return {Promise} + * + */ +const executeWorkflowStepVersion2 = (workflow, workflow_job_id, event, argsValues, job) => { + + if (!event || !event._id) { + return + } + + const graph = new graphlib.json.read(workflow.graph) + const nodeV = event.emitter_id.toString() + + const nodes = graph.successors(nodeV) + if (!nodes || (Array.isArray(nodes) && nodes.length === 0)) { + return + } + + const promises = [] + for (let nodeW of nodes) { + const edgeLabel = graph.edge(nodeV, nodeW) + if (edgeLabel === event.name) { + promises.push( + Task.findById(nodeW) + .then(task => { + if (!task) { + throw new Error(`workflow step ${nodeW} is missing`) + } + + const { user, dynamic_settings } = ifTriggeredByJobSettings(job) + const createPromise = createJob({ + user, + task, + task_arguments_values: argsValues, + dynamic_settings, + workflow, + workflow_job_id, + origin: JobConstants.ORIGIN_WORKFLOW + }) + + createPromise.catch(err => { return err }) + return createPromise + }) + ) + } + } + + return Promise.all(promises) +} + /** * @param {Event} event entity to process * @param {Job} job the job that generates the event * @param {Mixed} data event data, this is the job.output */ const triggerWorkflowByEvent = async ({ event, data, job }) => { + if (!event || !event._id) { + return + } + const workflows = await Workflow.find({ triggers: event._id }) if (workflows.length===0) { return } diff --git a/core/service/file.js b/core/service/file.js index c77544ff..be14225e 100644 --- a/core/service/file.js +++ b/core/service/file.js @@ -114,12 +114,34 @@ module.exports = { delete data.keyname this.createFromText({ - content: Buffer.from(template.data, 'base64').toString('utf8'), + text: Buffer.from(template.data, 'base64').toString('utf8'), metadata: data, storename: customer.name, filename: data.filename }, done) }, + create (input) { + return new Promise((resolve, reject) => { + const { customer } = input + const props = Object.assign({}, input, { + customer: customer._id, + customer_id: customer._id, + customer_name: customer.name, + template: null, + template_id: null + }) + + this.createFromText({ + metadata: props, + text: input.data, + filename: props.filename, + storename: customer.name + }, (err, file) => { + if (err) { reject(err) } + else { resolve(file) } + }) + }) + }, /** * * @summary create a file from it's content. all metadata must be provided. save content in the files storage and metadata in the database @@ -131,29 +153,29 @@ module.exports = { * */ createFromText (input, done) { - let { content } = input + const { text, storename, filename, metadata } = input logger.log('saving file in the store') - FileHandler.storeText({ - storename: input.storename, - filename: input.filename, - text: input.content - }, (err, storeData) => { + FileHandler.storeText({ storename, filename, text }, (err, storeData) => { if (err) { logger.error(err) return done(err) - } else { - let props = Object.assign({}, input.metadata) - props.keyname = storeData.keyname - props.md5 = crypto.createHash('md5').update(input.content).digest('hex') - props._type = 'Script' // force to create all files as scripts - - let script = FileModel.Script(props) - script.save( (err, model) => { - if (err) { logger.error(err) } - done(err, model) - }) } + + const props = Object.assign({}, metadata) + props.keyname = storeData.keyname + props.md5 = crypto + .createHash('md5') + .update(text) + .digest('hex') + + props._type = 'Script' // force to create all files as scripts + + const script = FileModel.Script(props) + script.save( (err, model) => { + if (err) { logger.error(err) } + done(err, model) + }) }) }, /** diff --git a/core/service/host/index.js b/core/service/host/index.js index d5311106..2a95c397 100644 --- a/core/service/host/index.js +++ b/core/service/host/index.js @@ -362,18 +362,10 @@ const fetchTaskTriggers = async (triggers) => { * @param {Customer} input.customer * @param {User} input.user * @param {Object} input.info - * @property {String} input.info.agent_version - * @property {String} input.info.ip - * @property {String} input.info.os_name - * @property {String} input.info.os_version - * @property {String} input.info.state * @param {Function(Error,Object)} next */ HostService.register = (input, next) => { - const hostname = input.hostname - const customer = input.customer - const info = input.info - const user = input.user + const { hostname, customer, user } = input logger.log('registering new host "%s"', hostname) @@ -382,18 +374,8 @@ HostService.register = (input, next) => { customer_id: customer._id, creation_date: new Date(), last_update: new Date(), - hostname: hostname, - ip: info.ip, - os_name: info.os_name, - os_version: info.os_version, - agent_version: info.agent_version, - state: info.state - }, (err, host) => { - if (err) { - logger.error(err) - return next(err) - } - + hostname + }).then(host => { logger.log('host registered. creating host resource') const data = { @@ -410,11 +392,12 @@ HostService.register = (input, next) => { description: host.hostname } - createHostResource(host, data, (err, payload) => { - if (err) { return next(err) } - logger.log('host %s resource created', hostname) - next(null, payload) + App.resource.create(data).then( resource => { + next(null, { host, resource }) }) + }).catch(err => { + logger.error(err) + next(err) }) } @@ -462,31 +445,6 @@ HostService.disableHostsByCustomer = (customer, doneFn) => { }); } -/** - * Create a resource for the host - * - * @summary Create host resource - * @param {Host} host - * @param {Object} data - * @property {Customer} data.customer - * @property {Mixed} ... many more properties - * @param {Function(Error,Object)} next - */ -const createHostResource = (host, data, next) => { - const customer = data.customer - - App.resource.create(data, (err, result) => { - if (err) { - logger.error(err) - return next(err) - } - - logger.log('host resource created') - const resource = result.resource - next(null, { host, resource }) - }) -} - /** * * Given an task, extract the triggers for monitors and tasks that belongs diff --git a/core/service/job/index.js b/core/service/job/index.js index 87c05550..04996a41 100644 --- a/core/service/job/index.js +++ b/core/service/job/index.js @@ -247,8 +247,8 @@ module.exports = { workflow_job_id: job.workflow_job_id, task_id: job.task_id, task: { - id: job.task_id.toString(), - _id: job.task_id.toString(), + id: job.task_id?.toString(), + _id: job.task_id?.toString(), } } } @@ -540,7 +540,7 @@ module.exports = { process.nextTick(() => { RegisterOperation.submit(Constants.UPDATE, TopicsConstants.job.crud, { job, user }) App.scheduler.cancelScheduledTimeoutVerificationJob(job) // async - dispatchFinishedTaskExecutionEvent(job) + dispatchFinishedJobExecutionEvent(job) emitJobFinishedNotification({ job }) }) } catch (err) { @@ -1059,7 +1059,7 @@ const cancelJobNextLifecycle = (job) => { * @return {Promise} * */ -const dispatchFinishedTaskExecutionEvent = async (job) => { +const dispatchFinishedJobExecutionEvent = async (job) => { try { const { task_id, trigger_name } = job let topic @@ -1073,10 +1073,10 @@ const dispatchFinishedTaskExecutionEvent = async (job) => { name: trigger_name }) - if (!event) { - let warn = `no handler defined for event named ${trigger_name} of task ${task_id}` - return logger.error(warn) - } + //if (!event) { + // const msg = `no handler defined for event named ${trigger_name} of task ${task_id}` + // throw new Error(msg) + //} // trigger task execution event within a workflow if (job.workflow_id && job.workflow_job_id) { @@ -1092,7 +1092,9 @@ const dispatchFinishedTaskExecutionEvent = async (job) => { job }) } catch (err) { - if (err) { return logger.error(err) } + if (err) { + return logger.error(err) + } } } diff --git a/core/service/scheduler.js b/core/service/scheduler.js index 85315d1b..20a26bac 100644 --- a/core/service/scheduler.js +++ b/core/service/scheduler.js @@ -182,6 +182,15 @@ Scheduler.prototype = { ] }) }, + // deletes ALL schedules for a given task + unscheduleWorkflow (workflow) { + return this.agenda.cancel({ + $and: [ + { name: SchedulerConstants.AGENDA_WORKFLOW }, + { 'data.workflow_id': workflow._id }, + ] + }) + }, /** * @param {Job} job * @return {Promise} diff --git a/core/service/task.js b/core/service/task.js index bcaddc0e..5508ba9f 100644 --- a/core/service/task.js +++ b/core/service/task.js @@ -1,4 +1,3 @@ -'use strict' const App = require('../app') @@ -8,9 +7,7 @@ const logger = require('../lib/logger')('service:task') const Tag = require('../entity/tag').Entity const Host = require('../entity/host').Entity const Task = require('../entity/task').Entity -const TaskFactory = require('../entity/task').Factory const TaskEvent = require('../entity/event').TaskEvent -//const Script = require('../entity/file').Script const Job = require('../entity/job').Job const Constants = require('../constants') const LifecycleConstants = require('../constants/lifecycle') @@ -21,8 +18,32 @@ const TaskTemplate = require('../entity/task/template') // var filter = require('../router/param-filter'); const FetchBy = require('../lib/fetch-by') +const ErrorHandler = require('../lib/error-handler') +const { ClientError, ServerError } = ErrorHandler module.exports = { + /** + * @return {Promise} + */ + factory (props) { + validateProperties(props) + + return Factory.create(props) + }, + async destroy (taskId) { + const task = await App.Models.Task.Task.findById(taskId) + if (!task) { + logger.error(`Task not found ${taskId}`) + return + } + + return Promise.all([ + task.remove(), + App.scheduler.unscheduleTask(task), + App.Models.Event.Event.deleteMany({ emitter_id: task._id }), + App.Models.Job.Job.deleteMany({ task_id: task._id.toString() }) + ]) + }, /** * @summary Remove task * @param {Object} options @@ -180,19 +201,9 @@ module.exports = { logger.log('creating task') logger.data(input) - const customer = input.customer - const task = TaskFactory.create(input) - - let errors = task.validateSync() - if (errors) { - let err = new Error('TaskValidationError') - err.statusCode = 400 - err.errors = errors - throw err - } - - await task.save() + const task = await this.factory(input) + const customer = input.customer createTags(input.tags, customer) createTaskEvents(task, customer) @@ -412,7 +423,9 @@ module.exports = { customer: customer, user_id: user.id, user: user, - source_model_id: task.id + source_model_id: task.id, + _id: undefined, + secret: undefined }) const template = TaskTemplate.Factory.create(data) @@ -442,6 +455,41 @@ module.exports = { } } +const validateProperties = (input) => { + const errors = new ErrorHandler() + + if (!input.name) { errors.required('name', input.name) } + if (!input.type) { errors.required('type', input.type) } + + if ( + input.type === TaskConstants.TYPE_SCRIPT || + input.type === TaskConstants.TYPE_SCRAPER + ) { + if (!input.host_id) { errors.required('host', req.host) } + } + + if (input.type === TaskConstants.TYPE_SCRIPT) { + if (!input.script_id && !input.script) { + errors.required('script', [input.script_id, input.script]) + } + + if (!input.script_runas) { + errors.required('script_runas', input.script_runas) + } + } + + if (input.type === TaskConstants.TYPE_APPROVAL) { } + if (input.type === TaskConstants.TYPE_SCRAPER) { } + if (input.type === TaskConstants.TYPE_DUMMY) { } + if (input.type === TaskConstants.TYPE_NOTIFICATION) { } + + if (errors.hasErrors()) { + const err = new ClientError('TaskValidationError', {statusCode: 400}) + err.errors = errors + throw err + } +} + // not yet const sendTaskUpdatedEventNotification = (task) => { return @@ -488,3 +536,76 @@ const createTags = (tags, customer) => { Tag.create(tags, customer) } } + +const Factory = { + async create (input) { + delete input._type + delete input.creation_date + delete input.last_update + delete input.secret + + if (input.hasOwnProperty('allows_dynamic_settings') === false) { + input.allows_dynamic_settings = false + } + + if (FactoryMethod.hasOwnProperty(input.type)) { + const task = await FactoryMethod[input.type](input) + + const errors = task.validateSync() + if (errors) { + const err = new ClientError('TaskValidationError') + err.statusCode = 400 + err.errors = errors + throw err + } + return task.save() + } + throw new Error('Invalid type error: ' + input.type) + } +} + +const FactoryMethod = {} +FactoryMethod[ TaskConstants.TYPE_SCRAPER ] = App.Models.Task.ScraperTask +FactoryMethod[ TaskConstants.TYPE_APPROVAL ] = App.Models.Task.ApprovalTask +FactoryMethod[ TaskConstants.TYPE_DUMMY ] = App.Models.Task.DummyTask +FactoryMethod[ TaskConstants.TYPE_SCRIPT ] = async function (input) { + let task = new App.Models.Task.ScriptTask(input) + // keep backward compatibility with script_arguments + task.script_arguments = input.task_arguments + + if (input.script_runas) { + task.script_runas = input.script_runas + if (/%script%/.test(input.script_runas) === false) { + task.script_runas += ' %script%' + } + } + + if (input.script_id) { + task.script = input.script_id + } else if (input.script) { + if (input.script.id) { + const id = input.script.id + input.script = id + input.script_id = id + } else { + const props = input.script + props.customer = input.customer + const script = await App.file.create(props) + task.script_id = script._id + task.script = script._id + } + } else { + // ?? + } + + return task +} +FactoryMethod[ TaskConstants.TYPE_NOTIFICATION ] = function (input) { + if ( + !Array.isArray(input.task_arguments) || + input.task_arguments.length === 0 + ) { + delete input.task_arguments + } + return new App.Models.Task.NotificationTask(input) +} diff --git a/docs/README.md b/docs/README.md index 607a741a..ac497dac 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,12 +1,13 @@ # TheEye Supervisor Core API -## What is TheEye? +## ¿Qué es TheEye? -
TheEye is a process automation platform developed in NodeJS. Best used as BPM, Rapid Backoffice Development (RDA) and processes' hub. -Technically TheEye is a choreographer + + TheEye es una plataforma de automatización de procesos desarrollada en NodeJS. Puede usarla como BPM, Rapid Backoffice Development (RDA) y nucleo de procesos. +Técnicamente, TheEye es un orquestrador.
@@ -25,47 +26,62 @@ Technically TheEye is a choreographer -## Architecture +## Arquitectura ![Image of TheEye-overview](images/TheEye-core-Architect.png) -If you want more information please read the https://documentation.theeye.io +Para más información por favor revise la documentación en https://documentation.theeye.io/ -## Environment settings +## Opciones de entorno -Provide this env variables to change the initial behaviour of the core Api. Once started cannot be changed. +Modifique estas variables de entorno para cambiar el comportamiento inicial de la API. No se pueden cambiar luego de la inicialización. +* Rest API - API para interactuar con los recursos de TheEye. https://documentation.theeye.io/api/auth/ -* Rest API - Api to interactar with TheEye resources. https://documentation.theeye.io/api/auth/ +* Sistema de Monitoreo - Funciona como un proceso en segundo plano. Chequea el estado de los Monitores. -* Monitoring System - It works as a background process. Will check Monitors status. +* API comandante interna (Solo escucha en el puerto 6666 en localhost) - Esta API no está documentada. Se usa solamente con propósitos de administración interna. -* Internal commander API (listen on port 6666 only localhost) - This API is not documented. It is used only for internal management purpose. +### Configuración de entorno -### Environment configuration +#### Configuración básica -Basic configuration +| Nombre de la Variable | Uso | +| ---------------------------- | --- | +| PORT | Cambia el puerto de la Rest API. Por defecto 60080 | +| NODE_ENV | El archivo del que la API debe sacar la configuración. | +| DEBUG | Activa/desactiva el módulo debug. [Más información](https://www.npmjs.com/package/debug) | +| THEEYE_NODE_HOSTNAME | Extiende el módulo debug. Agrega el hostname para depurar el output y define el Hostname en contenedores Docker | +| VERSION | Versión de la API. Si no se provee se intentará usar la versión definida en git. | +| CONFIG_NOTIFICATIONS_API_URL | URL de destino para el sistema de notificaciones | -| Variable Name | Usage | -| ----- | ----- | -| PORT | change rest api port. default 60080 | -| NODE_ENV | choose the configuration file that the api should use. | -| DEBUG | enabled/disable the debug module. check npm debug module for more information | -| THEEYE_NODE_HOSTNAME | this features extends the debug module. add the hostname to debug output and used to define a Hostname on Dockers | -| VERSION | api version. if not provided will try to detected the version using git. | -| CONFIG_NOTIFICATIONS_API_URL | target notification system url | +#### Control de componentes -Components Control. Can be configured to do one o more things (or nothing) +Puede configurarse para una o más cosas (o ninguna) -| Variable Name | Usage | -| ----- | ----- | -| COMMANDER_DISABLED | disable internal commander api | -| MONITORING_DISABLED | disable monitoring system. system monitors will not be checked anymore. will only change when bots and agents send updates | -| API_DISABLED | disable rest api | -| SCHEDULER_JOBS_DISABLED | disable internal scheduler execution. scheduler-jobs will be created using the rest api but task will never be executed. theeye-jobs execution timeout will be never checked. | +| Nombre de la Variable | Uso | +| ----------------------- | --- | +| COMMANDER_DISABLED | Desactiva la API comandante interna | +| MONITORING_DISABLED | Desactiva el monitoreo del sistema. Los monitores del sistema no van a revisarse más, solo van a actualizarse cuando los bots y agentes envíen updates | +| API_DISABLED | Desactiva la Rest API | +| SCHEDULER_JOBS_DISABLED | Desactiva la ejecución del scheduler interno. Los jobs programados se seguiran creando usando la Rest API pero la tarea nunca se ejecutará. El timeout de la ejecución nunca se revisará. | -### Start development sample +### Ejemplo para iniciar el desarrollo `DEBUG=*eye* NODE_ENV=localdev MONITORING_DISABLED= SCHEDULER_JOBS_DISABLED= npx nodemon --inspect $PWD/core/main.js` + +## Changelog + +TheEye se actualiza frecuentemente. En caso de hostear su propio entorno, es recomendable revisar periódicamente si hay actualizaciones disponibles para mantener su instalación al día con los últimos parches y features. + +El changelog de TheEye se encuentra [aquí](https://github.com/theeye-io-team/theeye-changelog). + +Nuestro entorno SaaS [app.theeye.io](http://app.theeye.io) está siempre al día con la última versión estable. + +Para conocer la versión de cada componentes puede consultar el dashboard web dentro de la pestaña *Help*, o hacer un GET request a las APIS. Es habitual que todos los componentes sean actualizados en cada release, por lo que es necesario verificar las versiones de todos los componentes y actualizarlos en el mismo momento ya que suelen tener dependencias entre si. + +El supervisor [`supervisor.theeye.io/api/status`](https://supervisor.theeye.io/api/status). + +El Gateway [`app.theeye.io/api/status`](https://app.theeye.io/api/status). diff --git a/docs/_navbar.md b/docs/_navbar.md new file mode 100644 index 00000000..b1ca8016 --- /dev/null +++ b/docs/_navbar.md @@ -0,0 +1,3 @@ +- Translations + - [:us: English](en/) + - [:argentina: Español](/) \ No newline at end of file diff --git a/docs/_sidebar.md b/docs/_sidebar.md index d09929ef..3d9cb007 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -1,10 +1,10 @@ -- [API for developers](./) -- [Enable access to APIs](./auth.md) -- [Indicators](./indicators/) -- Tasks - - [Basics](./tasks/) - - [Arguments](./tasks/arguments.md) -- [Monitors](./monitors/) -- [Jobs](./jobs/) -- [Webhooks](./webhooks/) -- [Sync](./sync/) \ No newline at end of file +- [API para desarrolladores](/) +- [Habilitar acceso a las APIs](/auth.md) +- [Indicadores](/indicators/) +- Tareas + - [Introducción](/tasks/) + - [Argumentos](/tasks/arguments.md) +- [Monitores](/monitors/) +- [Jobs](/jobs/) +- [Webhooks](/webhooks/) +- [Sync](/sync/) \ No newline at end of file diff --git a/docs/auth.md b/docs/auth.md index 46d8f598..8bd59695 100644 --- a/docs/auth.md +++ b/docs/auth.md @@ -1,36 +1,53 @@ [![theeye.io](images/logo-theeye-theOeye-logo2.png)](https://theeye.io/en/index.html) -# Integration through API +# Integraión mediante la API + +## Acceder a la API + +Se puede acceder a la API de distintas maneras: + +- [Integraión mediante la API](#integraión-mediante-la-api) + - [Acceder a la API](#acceder-a-la-api) + - [Authenticación básica](#authenticación-básica) + - [Autenticación al portador (Bearer Authentication)](#autenticación-al-portador-bearer-authentication) + - [Recursos con clave secreta propia](#recursos-con-clave-secreta-propia) + - [Tokens de integración (Integration Tokens)](#tokens-de-integración-integration-tokens) ----- -## Accessing the API +### Authenticación básica +Se puede hacer un request al endpoint de inicio de sesión de la API usando el protocolo de autenticación básica HTTP. Como la API de TheEye se comunica con el cliente por HTTPS, se recomienda enviar un POST request de autenticación a la siguiente dirección, reemplazando `${usuario}` y `${contraseña}` acorde: -* Integration Tokens +```javascript +`https://${usuario}:${contraseña}@app.theeye.io/api/auth/login` +``` -* Basic Authentication & Bearer Authentication +Este request devuelve un `access_token`, el cual es una string codificada de [JWT](https://jwt.io), la cual contiene el ID del ususario, la fecha de creación y de caducidad del Token. Este token se requiere para la mayoría de las operaciones de la API, y se tiene que enviar con los requests como se explica en la siguiente sección -* Secret Token +### Autenticación al portador (Bearer Authentication) ------ +Una vez que haya recibido su `access_token`, será necesario incluirlo en sus requests como el Bearer Token para indicarle a la API el usuario del que proviene. -### Integration Tokens +Los tokens de acceso obtenidos mediante autenticación básica son válidos durante 3 horas -An Access Token is a credential that can be used by an application to access an API. Access Tokens can be either an opaque string or a JSON web token. They inform the API that the bearer of the token has been authorized to access the API and perform specific actions specified by the scope that has been granted. +### Recursos con clave secreta propia -To verify that access to the APIs has been enabled: -- Log in to TheEye Administration Console. -- You must use an administrator account. - - On the main page of the administration console, go to setting then to credentials. You can see the list of "Integration Tokens". +Algunos recursos de la API de TheEye tienen una clave secreta propia, independiente de la autenticación de usuario. Por ejemplo, se pueden ejecutar tareas sabiendo su ID y su clave secreta. [Más información](/tasks/#usando-la-secret-key-de-la-tarea-recomendado) -![dashboard_settings_credentials](images/dashboard_setting_credentials.png) +### Tokens de integración (Integration Tokens) +Los tokens de integración permiten acceder a la API. Son secuencias de caracteres auto-generadas utilizando la librería JWT (JSON Web Token). ------ +Los tokens de integración son tokens de acceso (access token) que, a diferencia de los tokens de acceso de sesión generados mediante autenticación básica, no tienen tiempo de expiración y pueden ser utilizados indefinidamente o hasta que un administrador lo elimine del sistema. +Es conveniente tener bien identificado donde serán utilizados y renovarlos periódicamente. -### Basic Authentication & Bearer Authentication ------ +Para revisar si se encuentra tokens de integración activos: + +- Inicie sesión en la consola de administración de TheEye **con una cuenta de ADMINISTRADOR** + +- En la página principal, diríjase a *Settings* y seleccione *credentials*. Allí se puede acceder a *Integration Tokens* donde se podrá ver los tokens de integración creados + +![dashboard_settings_credentials](images/dashboard_setting_credentials.png) -### Access resources with Secret Token diff --git a/docs/en/README.md b/docs/en/README.md new file mode 100644 index 00000000..607a741a --- /dev/null +++ b/docs/en/README.md @@ -0,0 +1,71 @@ +# TheEye Supervisor Core API + +## What is TheEye? + + + + + + +
TheEye is a process automation platform developed in NodeJS. Best used as BPM, Rapid Backoffice Development (RDA) and processes' hub. +Technically TheEye is a choreographer +
+
+
+
+ + + + + + + +
+
+
+
+ +## Architecture + +![Image of TheEye-overview](images/TheEye-core-Architect.png) + +If you want more information please read the https://documentation.theeye.io + +## Environment settings + +Provide this env variables to change the initial behaviour of the core Api. Once started cannot be changed. + + +* Rest API - Api to interactar with TheEye resources. https://documentation.theeye.io/api/auth/ + +* Monitoring System - It works as a background process. Will check Monitors status. + +* Internal commander API (listen on port 6666 only localhost) - This API is not documented. It is used only for internal management purpose. + +### Environment configuration + +Basic configuration + +| Variable Name | Usage | +| ----- | ----- | +| PORT | change rest api port. default 60080 | +| NODE_ENV | choose the configuration file that the api should use. | +| DEBUG | enabled/disable the debug module. check npm debug module for more information | +| THEEYE_NODE_HOSTNAME | this features extends the debug module. add the hostname to debug output and used to define a Hostname on Dockers | +| VERSION | api version. if not provided will try to detected the version using git. | +| CONFIG_NOTIFICATIONS_API_URL | target notification system url | + + +Components Control. Can be configured to do one o more things (or nothing) + + +| Variable Name | Usage | +| ----- | ----- | +| COMMANDER_DISABLED | disable internal commander api | +| MONITORING_DISABLED | disable monitoring system. system monitors will not be checked anymore. will only change when bots and agents send updates | +| API_DISABLED | disable rest api | +| SCHEDULER_JOBS_DISABLED | disable internal scheduler execution. scheduler-jobs will be created using the rest api but task will never be executed. theeye-jobs execution timeout will be never checked. | + +### Start development sample + +`DEBUG=*eye* NODE_ENV=localdev MONITORING_DISABLED= SCHEDULER_JOBS_DISABLED= npx nodemon --inspect $PWD/core/main.js` diff --git a/docs/en/_sidebar.md b/docs/en/_sidebar.md new file mode 100644 index 00000000..5149d524 --- /dev/null +++ b/docs/en/_sidebar.md @@ -0,0 +1,10 @@ +- [API for developers](en) +- [Enable access to APIs](enauth.md) +- [Indicators](enindicators/) +- Tasks + - [Basics](entasks/) + - [Arguments](entasks/arguments.md) +- [Monitors](enmonitors/) +- [Jobs](enjobs/) +- [Webhooks](enwebhooks/) +- [Sync](ensync/) diff --git a/docs/en/auth.md b/docs/en/auth.md new file mode 100644 index 00000000..46d8f598 --- /dev/null +++ b/docs/en/auth.md @@ -0,0 +1,36 @@ +[![theeye.io](images/logo-theeye-theOeye-logo2.png)](https://theeye.io/en/index.html) + +# Integration through API + +----- + +## Accessing the API + + +* Integration Tokens + +* Basic Authentication & Bearer Authentication + +* Secret Token + +----- + +### Integration Tokens + +An Access Token is a credential that can be used by an application to access an API. Access Tokens can be either an opaque string or a JSON web token. They inform the API that the bearer of the token has been authorized to access the API and perform specific actions specified by the scope that has been granted. + +To verify that access to the APIs has been enabled: +- Log in to TheEye Administration Console. +- You must use an administrator account. + - On the main page of the administration console, go to setting then to credentials. You can see the list of "Integration Tokens". + +![dashboard_settings_credentials](images/dashboard_setting_credentials.png) + + +----- + +### Basic Authentication & Bearer Authentication + +----- + +### Access resources with Secret Token diff --git a/docs/en/images/ACLs.png b/docs/en/images/ACLs.png new file mode 100644 index 00000000..601e3fd0 Binary files /dev/null and b/docs/en/images/ACLs.png differ diff --git a/docs/en/images/FirstTimeLogin.gif b/docs/en/images/FirstTimeLogin.gif new file mode 100644 index 00000000..6aaf4d2c Binary files /dev/null and b/docs/en/images/FirstTimeLogin.gif differ diff --git a/docs/en/images/FirstTimeLogin.jpg b/docs/en/images/FirstTimeLogin.jpg new file mode 100644 index 00000000..34dbf2ff Binary files /dev/null and b/docs/en/images/FirstTimeLogin.jpg differ diff --git a/docs/en/images/FirstTimeLogin.png b/docs/en/images/FirstTimeLogin.png new file mode 100644 index 00000000..6e0af98c Binary files /dev/null and b/docs/en/images/FirstTimeLogin.png differ diff --git a/docs/en/images/NestedMonitors.jpg b/docs/en/images/NestedMonitors.jpg new file mode 100644 index 00000000..d60e39d4 Binary files /dev/null and b/docs/en/images/NestedMonitors.jpg differ diff --git a/docs/en/images/NestedMonitorsSetup.jpg b/docs/en/images/NestedMonitorsSetup.jpg new file mode 100644 index 00000000..7d1cd50e Binary files /dev/null and b/docs/en/images/NestedMonitorsSetup.jpg differ diff --git a/docs/en/images/SHLOB.gif b/docs/en/images/SHLOB.gif new file mode 100644 index 00000000..9569e489 Binary files /dev/null and b/docs/en/images/SHLOB.gif differ diff --git a/docs/en/images/Settings.jpg b/docs/en/images/Settings.jpg new file mode 100644 index 00000000..cbadcfa3 Binary files /dev/null and b/docs/en/images/Settings.jpg differ diff --git a/docs/en/images/TheEye-Agent-AWS-Install-curl.png b/docs/en/images/TheEye-Agent-AWS-Install-curl.png new file mode 100644 index 00000000..40abe7bf Binary files /dev/null and b/docs/en/images/TheEye-Agent-AWS-Install-curl.png differ diff --git a/docs/en/images/TheEye-Agent-AWS-Install.jpg b/docs/en/images/TheEye-Agent-AWS-Install.jpg new file mode 100644 index 00000000..1df2e749 Binary files /dev/null and b/docs/en/images/TheEye-Agent-AWS-Install.jpg differ diff --git a/docs/en/images/TheEye-Agent-Docker-Install.jpg b/docs/en/images/TheEye-Agent-Docker-Install.jpg new file mode 100644 index 00000000..48423983 Binary files /dev/null and b/docs/en/images/TheEye-Agent-Docker-Install.jpg differ diff --git a/docs/en/images/TheEye-Agent-Full-list.jpg b/docs/en/images/TheEye-Agent-Full-list.jpg new file mode 100644 index 00000000..b79e0b25 Binary files /dev/null and b/docs/en/images/TheEye-Agent-Full-list.jpg differ diff --git a/docs/en/images/TheEye-Agent-Linux-Install.jpg b/docs/en/images/TheEye-Agent-Linux-Install.jpg new file mode 100644 index 00000000..fd64d256 Binary files /dev/null and b/docs/en/images/TheEye-Agent-Linux-Install.jpg differ diff --git a/docs/en/images/TheEye-Agent-Windows-Install.gif b/docs/en/images/TheEye-Agent-Windows-Install.gif new file mode 100644 index 00000000..1fd6a188 Binary files /dev/null and b/docs/en/images/TheEye-Agent-Windows-Install.gif differ diff --git a/docs/en/images/TheEye-Agent-Windows-Install.jpg b/docs/en/images/TheEye-Agent-Windows-Install.jpg new file mode 100644 index 00000000..494e50e9 Binary files /dev/null and b/docs/en/images/TheEye-Agent-Windows-Install.jpg differ diff --git a/docs/en/images/TheEye-Of-Sauron.png b/docs/en/images/TheEye-Of-Sauron.png new file mode 100644 index 00000000..f21bb741 Binary files /dev/null and b/docs/en/images/TheEye-Of-Sauron.png differ diff --git a/docs/en/images/TheEye-core-Architect.png b/docs/en/images/TheEye-core-Architect.png new file mode 100644 index 00000000..ec37782b Binary files /dev/null and b/docs/en/images/TheEye-core-Architect.png differ diff --git a/docs/en/images/TheEye_redes-sociales-linkedin.png b/docs/en/images/TheEye_redes-sociales-linkedin.png new file mode 100644 index 00000000..6281af0f Binary files /dev/null and b/docs/en/images/TheEye_redes-sociales-linkedin.png differ diff --git a/docs/en/images/acls-1.png b/docs/en/images/acls-1.png new file mode 100644 index 00000000..601e3fd0 Binary files /dev/null and b/docs/en/images/acls-1.png differ diff --git a/docs/en/images/advancedLaunch.png b/docs/en/images/advancedLaunch.png new file mode 100644 index 00000000..1492b24d Binary files /dev/null and b/docs/en/images/advancedLaunch.png differ diff --git a/docs/en/images/advancedoptionstask.jpg b/docs/en/images/advancedoptionstask.jpg new file mode 100644 index 00000000..c550cd62 Binary files /dev/null and b/docs/en/images/advancedoptionstask.jpg differ diff --git a/docs/en/images/advancedoptionstask.png b/docs/en/images/advancedoptionstask.png new file mode 100644 index 00000000..c550cd62 Binary files /dev/null and b/docs/en/images/advancedoptionstask.png differ diff --git a/docs/en/images/alertsandnotifications.jpg b/docs/en/images/alertsandnotifications.jpg new file mode 100644 index 00000000..617a73a7 Binary files /dev/null and b/docs/en/images/alertsandnotifications.jpg differ diff --git a/docs/en/images/copytask.gif b/docs/en/images/copytask.gif new file mode 100644 index 00000000..e2818698 Binary files /dev/null and b/docs/en/images/copytask.gif differ diff --git a/docs/en/images/createIndicator.gif b/docs/en/images/createIndicator.gif new file mode 100644 index 00000000..2d35faca Binary files /dev/null and b/docs/en/images/createIndicator.gif differ diff --git a/docs/en/images/createMonitorFile.gif b/docs/en/images/createMonitorFile.gif new file mode 100644 index 00000000..85e4178e Binary files /dev/null and b/docs/en/images/createMonitorFile.gif differ diff --git a/docs/en/images/createtask.gif b/docs/en/images/createtask.gif new file mode 100644 index 00000000..7ae0599b Binary files /dev/null and b/docs/en/images/createtask.gif differ diff --git a/docs/en/images/createworkflow.gif b/docs/en/images/createworkflow.gif new file mode 100644 index 00000000..0625a484 Binary files /dev/null and b/docs/en/images/createworkflow.gif differ diff --git a/docs/en/images/dashboard.png b/docs/en/images/dashboard.png new file mode 100644 index 00000000..3975a431 Binary files /dev/null and b/docs/en/images/dashboard.png differ diff --git a/docs/en/images/dashboard_monitors_workflow.png b/docs/en/images/dashboard_monitors_workflow.png new file mode 100644 index 00000000..82c1a252 Binary files /dev/null and b/docs/en/images/dashboard_monitors_workflow.png differ diff --git a/docs/en/images/dashboard_setting_credentials.png b/docs/en/images/dashboard_setting_credentials.png new file mode 100644 index 00000000..92b5c512 Binary files /dev/null and b/docs/en/images/dashboard_setting_credentials.png differ diff --git a/docs/en/images/dashboard_setting_intergation_kibana.png b/docs/en/images/dashboard_setting_intergation_kibana.png new file mode 100644 index 00000000..ea40c151 Binary files /dev/null and b/docs/en/images/dashboard_setting_intergation_kibana.png differ diff --git a/docs/en/images/dashboard_workflow_script_and_notification-00.png b/docs/en/images/dashboard_workflow_script_and_notification-00.png new file mode 100644 index 00000000..1cb71dae Binary files /dev/null and b/docs/en/images/dashboard_workflow_script_and_notification-00.png differ diff --git a/docs/en/images/dashboard_workflow_script_and_notification-01.png b/docs/en/images/dashboard_workflow_script_and_notification-01.png new file mode 100644 index 00000000..da80c234 Binary files /dev/null and b/docs/en/images/dashboard_workflow_script_and_notification-01.png differ diff --git a/docs/en/images/dashboard_workflow_script_and_notification-old.png b/docs/en/images/dashboard_workflow_script_and_notification-old.png new file mode 100644 index 00000000..d6f6d4c8 Binary files /dev/null and b/docs/en/images/dashboard_workflow_script_and_notification-old.png differ diff --git a/docs/en/images/dashboard_workflow_script_and_notification.png b/docs/en/images/dashboard_workflow_script_and_notification.png new file mode 100644 index 00000000..019d33d8 Binary files /dev/null and b/docs/en/images/dashboard_workflow_script_and_notification.png differ diff --git a/docs/en/images/exportecipe.gif b/docs/en/images/exportecipe.gif new file mode 100644 index 00000000..54380d51 Binary files /dev/null and b/docs/en/images/exportecipe.gif differ diff --git a/docs/en/images/firtsStepsScriptsCreate.jpg b/docs/en/images/firtsStepsScriptsCreate.jpg new file mode 100644 index 00000000..b89414d4 Binary files /dev/null and b/docs/en/images/firtsStepsScriptsCreate.jpg differ diff --git a/docs/en/images/firtsStepsTaskCreate.jpg b/docs/en/images/firtsStepsTaskCreate.jpg new file mode 100644 index 00000000..770f9730 Binary files /dev/null and b/docs/en/images/firtsStepsTaskCreate.jpg differ diff --git a/docs/en/images/fixedarg.gif b/docs/en/images/fixedarg.gif new file mode 100644 index 00000000..8e7cbe8f Binary files /dev/null and b/docs/en/images/fixedarg.gif differ diff --git a/docs/en/images/form_notification.gif b/docs/en/images/form_notification.gif new file mode 100644 index 00000000..ea5aca3e Binary files /dev/null and b/docs/en/images/form_notification.gif differ diff --git a/docs/en/images/form_notification.png b/docs/en/images/form_notification.png new file mode 100644 index 00000000..11081d59 Binary files /dev/null and b/docs/en/images/form_notification.png differ diff --git a/docs/en/images/image-01.png b/docs/en/images/image-01.png new file mode 100644 index 00000000..427ddbce Binary files /dev/null and b/docs/en/images/image-01.png differ diff --git a/docs/en/images/image-02.png b/docs/en/images/image-02.png new file mode 100644 index 00000000..2ed44eb1 Binary files /dev/null and b/docs/en/images/image-02.png differ diff --git a/docs/en/images/image-03.png b/docs/en/images/image-03.png new file mode 100644 index 00000000..79e570d0 Binary files /dev/null and b/docs/en/images/image-03.png differ diff --git a/docs/en/images/image-04.png b/docs/en/images/image-04.png new file mode 100644 index 00000000..76b24ade Binary files /dev/null and b/docs/en/images/image-04.png differ diff --git a/docs/en/images/image-05.png b/docs/en/images/image-05.png new file mode 100644 index 00000000..740b361f Binary files /dev/null and b/docs/en/images/image-05.png differ diff --git a/docs/en/images/image-06.png b/docs/en/images/image-06.png new file mode 100644 index 00000000..a307204f Binary files /dev/null and b/docs/en/images/image-06.png differ diff --git a/docs/en/images/image-07.png b/docs/en/images/image-07.png new file mode 100644 index 00000000..7f8f0c77 Binary files /dev/null and b/docs/en/images/image-07.png differ diff --git a/docs/en/images/image-08.png b/docs/en/images/image-08.png new file mode 100644 index 00000000..cf6a5e06 Binary files /dev/null and b/docs/en/images/image-08.png differ diff --git a/docs/en/images/image-09-old.png b/docs/en/images/image-09-old.png new file mode 100644 index 00000000..4ad4d91f Binary files /dev/null and b/docs/en/images/image-09-old.png differ diff --git a/docs/en/images/image-09.png b/docs/en/images/image-09.png new file mode 100644 index 00000000..defd6732 Binary files /dev/null and b/docs/en/images/image-09.png differ diff --git a/docs/en/images/image-10.png b/docs/en/images/image-10.png new file mode 100644 index 00000000..875ea6cc Binary files /dev/null and b/docs/en/images/image-10.png differ diff --git a/docs/en/images/image-11.png b/docs/en/images/image-11.png new file mode 100644 index 00000000..796228bc Binary files /dev/null and b/docs/en/images/image-11.png differ diff --git a/docs/en/images/image-12.png b/docs/en/images/image-12.png new file mode 100644 index 00000000..daa6223b Binary files /dev/null and b/docs/en/images/image-12.png differ diff --git a/docs/en/images/image-13.png b/docs/en/images/image-13.png new file mode 100644 index 00000000..f78d817f Binary files /dev/null and b/docs/en/images/image-13.png differ diff --git a/docs/en/images/image-16.png b/docs/en/images/image-16.png new file mode 100644 index 00000000..1dc1317d Binary files /dev/null and b/docs/en/images/image-16.png differ diff --git a/docs/en/images/image-17.png b/docs/en/images/image-17.png new file mode 100644 index 00000000..0457b8a2 Binary files /dev/null and b/docs/en/images/image-17.png differ diff --git a/docs/en/images/image-old.png b/docs/en/images/image-old.png new file mode 100644 index 00000000..31480806 Binary files /dev/null and b/docs/en/images/image-old.png differ diff --git a/docs/en/images/image.png b/docs/en/images/image.png new file mode 100644 index 00000000..84d5e1a4 Binary files /dev/null and b/docs/en/images/image.png differ diff --git a/docs/en/images/install_docker.png b/docs/en/images/install_docker.png new file mode 100644 index 00000000..85ea4ebc Binary files /dev/null and b/docs/en/images/install_docker.png differ diff --git a/docs/en/images/integration_elk_index_elasticsearch.png b/docs/en/images/integration_elk_index_elasticsearch.png new file mode 100644 index 00000000..c2a39d0b Binary files /dev/null and b/docs/en/images/integration_elk_index_elasticsearch.png differ diff --git a/docs/en/images/logical_access/Screenshot_1.png b/docs/en/images/logical_access/Screenshot_1.png new file mode 100644 index 00000000..c5988fe7 Binary files /dev/null and b/docs/en/images/logical_access/Screenshot_1.png differ diff --git a/docs/en/images/logical_access/Screenshot_2.png b/docs/en/images/logical_access/Screenshot_2.png new file mode 100644 index 00000000..fab13bb0 Binary files /dev/null and b/docs/en/images/logical_access/Screenshot_2.png differ diff --git a/docs/en/images/logical_access/Screenshot_3.png b/docs/en/images/logical_access/Screenshot_3.png new file mode 100644 index 00000000..18277827 Binary files /dev/null and b/docs/en/images/logical_access/Screenshot_3.png differ diff --git a/docs/en/images/logical_access/acl.png b/docs/en/images/logical_access/acl.png new file mode 100644 index 00000000..e7c434cc Binary files /dev/null and b/docs/en/images/logical_access/acl.png differ diff --git a/docs/en/images/logical_access/acl2.png b/docs/en/images/logical_access/acl2.png new file mode 100644 index 00000000..abd3a9a5 Binary files /dev/null and b/docs/en/images/logical_access/acl2.png differ diff --git a/docs/en/images/logical_access/acl3.png b/docs/en/images/logical_access/acl3.png new file mode 100644 index 00000000..58f340ea Binary files /dev/null and b/docs/en/images/logical_access/acl3.png differ diff --git a/docs/en/images/logical_access/acl4.png b/docs/en/images/logical_access/acl4.png new file mode 100644 index 00000000..bf2715af Binary files /dev/null and b/docs/en/images/logical_access/acl4.png differ diff --git a/docs/en/images/logical_access/acl5.png b/docs/en/images/logical_access/acl5.png new file mode 100644 index 00000000..f0a6945e Binary files /dev/null and b/docs/en/images/logical_access/acl5.png differ diff --git a/docs/en/images/logical_access/banco-comafi-logo.png b/docs/en/images/logical_access/banco-comafi-logo.png new file mode 100644 index 00000000..9e1bcd32 Binary files /dev/null and b/docs/en/images/logical_access/banco-comafi-logo.png differ diff --git a/docs/en/images/logical_access/cambiar_organizacion.png b/docs/en/images/logical_access/cambiar_organizacion.png new file mode 100644 index 00000000..d30565bd Binary files /dev/null and b/docs/en/images/logical_access/cambiar_organizacion.png differ diff --git a/docs/en/images/logical_access/editarapproval.png b/docs/en/images/logical_access/editarapproval.png new file mode 100644 index 00000000..e0efbff9 Binary files /dev/null and b/docs/en/images/logical_access/editarapproval.png differ diff --git a/docs/en/images/logical_access/editarapproval2.png b/docs/en/images/logical_access/editarapproval2.png new file mode 100644 index 00000000..267d9865 Binary files /dev/null and b/docs/en/images/logical_access/editarapproval2.png differ diff --git a/docs/en/images/logical_access/editarapproval3.png b/docs/en/images/logical_access/editarapproval3.png new file mode 100644 index 00000000..51019e3d Binary files /dev/null and b/docs/en/images/logical_access/editarapproval3.png differ diff --git a/docs/en/images/logical_access/filtro.png b/docs/en/images/logical_access/filtro.png new file mode 100644 index 00000000..a163b383 Binary files /dev/null and b/docs/en/images/logical_access/filtro.png differ diff --git a/docs/en/images/logical_access/filtro2.png b/docs/en/images/logical_access/filtro2.png new file mode 100644 index 00000000..3681c893 Binary files /dev/null and b/docs/en/images/logical_access/filtro2.png differ diff --git a/docs/en/images/logo-theeye-circle.png b/docs/en/images/logo-theeye-circle.png new file mode 100644 index 00000000..8dd7a884 Binary files /dev/null and b/docs/en/images/logo-theeye-circle.png differ diff --git a/docs/en/images/logo-theeye-docu-glasses.png b/docs/en/images/logo-theeye-docu-glasses.png new file mode 100644 index 00000000..9d0b0ad7 Binary files /dev/null and b/docs/en/images/logo-theeye-docu-glasses.png differ diff --git a/docs/en/images/logo-theeye-theOeye-logo2.png b/docs/en/images/logo-theeye-theOeye-logo2.png new file mode 100644 index 00000000..6d659685 Binary files /dev/null and b/docs/en/images/logo-theeye-theOeye-logo2.png differ diff --git a/docs/en/images/logo-theeye-theOeye.png b/docs/en/images/logo-theeye-theOeye.png new file mode 100644 index 00000000..6979fd37 Binary files /dev/null and b/docs/en/images/logo-theeye-theOeye.png differ diff --git a/docs/en/images/members.png b/docs/en/images/members.png new file mode 100644 index 00000000..7d9f3a99 Binary files /dev/null and b/docs/en/images/members.png differ diff --git a/docs/en/images/monitor_process.gif b/docs/en/images/monitor_process.gif new file mode 100644 index 00000000..253654dc Binary files /dev/null and b/docs/en/images/monitor_process.gif differ diff --git a/docs/en/images/monitor_script.gif b/docs/en/images/monitor_script.gif new file mode 100644 index 00000000..8968f9ac Binary files /dev/null and b/docs/en/images/monitor_script.gif differ diff --git a/docs/en/images/monitor_stats.gif b/docs/en/images/monitor_stats.gif new file mode 100644 index 00000000..04adc937 Binary files /dev/null and b/docs/en/images/monitor_stats.gif differ diff --git a/docs/en/images/mute-monitors.gif b/docs/en/images/mute-monitors.gif new file mode 100644 index 00000000..de31718f Binary files /dev/null and b/docs/en/images/mute-monitors.gif differ diff --git a/docs/en/images/mute-monitors.jpg b/docs/en/images/mute-monitors.jpg new file mode 100644 index 00000000..1f11c30b Binary files /dev/null and b/docs/en/images/mute-monitors.jpg differ diff --git a/docs/en/images/nestedmonitors.jpg b/docs/en/images/nestedmonitors.jpg new file mode 100644 index 00000000..d60e39d4 Binary files /dev/null and b/docs/en/images/nestedmonitors.jpg differ diff --git a/docs/en/images/nestedmonitorssetup.jpg b/docs/en/images/nestedmonitorssetup.jpg new file mode 100644 index 00000000..7d1cd50e Binary files /dev/null and b/docs/en/images/nestedmonitorssetup.jpg differ diff --git a/docs/en/images/newTaskDashboard.gif b/docs/en/images/newTaskDashboard.gif new file mode 100644 index 00000000..00a9e3f4 Binary files /dev/null and b/docs/en/images/newTaskDashboard.gif differ diff --git a/docs/en/images/newTaskDashboard.png b/docs/en/images/newTaskDashboard.png new file mode 100644 index 00000000..6fcc0ea2 Binary files /dev/null and b/docs/en/images/newTaskDashboard.png differ diff --git a/docs/en/images/new_dashboard.png b/docs/en/images/new_dashboard.png new file mode 100644 index 00000000..b4dd7b5b Binary files /dev/null and b/docs/en/images/new_dashboard.png differ diff --git a/docs/en/images/newtaskdashboard.png b/docs/en/images/newtaskdashboard.png new file mode 100644 index 00000000..6fcc0ea2 Binary files /dev/null and b/docs/en/images/newtaskdashboard.png differ diff --git a/docs/en/images/notification1.jpg b/docs/en/images/notification1.jpg new file mode 100644 index 00000000..b53d4cfc Binary files /dev/null and b/docs/en/images/notification1.jpg differ diff --git a/docs/en/images/notificationstab.jpg b/docs/en/images/notificationstab.jpg new file mode 100644 index 00000000..74b8aabc Binary files /dev/null and b/docs/en/images/notificationstab.jpg differ diff --git a/docs/en/images/quickinputtask.jpg b/docs/en/images/quickinputtask.jpg new file mode 100644 index 00000000..0af33362 Binary files /dev/null and b/docs/en/images/quickinputtask.jpg differ diff --git a/docs/en/images/quickinputtask.png b/docs/en/images/quickinputtask.png new file mode 100644 index 00000000..82c767be Binary files /dev/null and b/docs/en/images/quickinputtask.png differ diff --git a/docs/en/images/remove_docker.png b/docs/en/images/remove_docker.png new file mode 100644 index 00000000..d1206640 Binary files /dev/null and b/docs/en/images/remove_docker.png differ diff --git a/docs/en/images/resourcesList.jpg b/docs/en/images/resourcesList.jpg new file mode 100644 index 00000000..52d6d657 Binary files /dev/null and b/docs/en/images/resourcesList.jpg differ diff --git a/docs/en/images/resourcesList.png b/docs/en/images/resourcesList.png new file mode 100644 index 00000000..c014a8b6 Binary files /dev/null and b/docs/en/images/resourcesList.png differ diff --git a/docs/en/images/schedule.gif b/docs/en/images/schedule.gif new file mode 100644 index 00000000..7ef3c77e Binary files /dev/null and b/docs/en/images/schedule.gif differ diff --git a/docs/en/images/scriptsRunAsDefault.png b/docs/en/images/scriptsRunAsDefault.png new file mode 100644 index 00000000..170d7632 Binary files /dev/null and b/docs/en/images/scriptsRunAsDefault.png differ diff --git a/docs/en/images/scriptsRunAsPowershell.png b/docs/en/images/scriptsRunAsPowershell.png new file mode 100644 index 00000000..b85b379f Binary files /dev/null and b/docs/en/images/scriptsRunAsPowershell.png differ diff --git a/docs/en/images/selection_003.png b/docs/en/images/selection_003.png new file mode 100644 index 00000000..4f1dd225 Binary files /dev/null and b/docs/en/images/selection_003.png differ diff --git a/docs/en/images/settingsinstaller.gif b/docs/en/images/settingsinstaller.gif new file mode 100644 index 00000000..1ee35f49 Binary files /dev/null and b/docs/en/images/settingsinstaller.gif differ diff --git a/docs/en/images/settingsnotification1.jpg b/docs/en/images/settingsnotification1.jpg new file mode 100644 index 00000000..87074220 Binary files /dev/null and b/docs/en/images/settingsnotification1.jpg differ diff --git a/docs/en/images/settingsnotification2.jpg b/docs/en/images/settingsnotification2.jpg new file mode 100644 index 00000000..a043a0de Binary files /dev/null and b/docs/en/images/settingsnotification2.jpg differ diff --git a/docs/en/images/startbot.gif b/docs/en/images/startbot.gif new file mode 100644 index 00000000..034a795c Binary files /dev/null and b/docs/en/images/startbot.gif differ diff --git a/docs/en/images/startbot.jpg b/docs/en/images/startbot.jpg new file mode 100644 index 00000000..db6c166f Binary files /dev/null and b/docs/en/images/startbot.jpg differ diff --git a/docs/en/images/taskReport.jpg b/docs/en/images/taskReport.jpg new file mode 100644 index 00000000..3144492f Binary files /dev/null and b/docs/en/images/taskReport.jpg differ diff --git a/docs/en/images/taskReportMore.jpg b/docs/en/images/taskReportMore.jpg new file mode 100644 index 00000000..55b0207f Binary files /dev/null and b/docs/en/images/taskReportMore.jpg differ diff --git a/docs/en/images/taskexecution.jpg b/docs/en/images/taskexecution.jpg new file mode 100644 index 00000000..a986b13a Binary files /dev/null and b/docs/en/images/taskexecution.jpg differ diff --git a/docs/en/images/template.gif b/docs/en/images/template.gif new file mode 100644 index 00000000..e70c27fe Binary files /dev/null and b/docs/en/images/template.gif differ diff --git a/docs/en/images/template.jpg b/docs/en/images/template.jpg new file mode 100644 index 00000000..76d282b2 Binary files /dev/null and b/docs/en/images/template.jpg differ diff --git a/docs/en/images/triggerbyworkflow.gif b/docs/en/images/triggerbyworkflow.gif new file mode 100644 index 00000000..c5a9f09d Binary files /dev/null and b/docs/en/images/triggerbyworkflow.gif differ diff --git a/docs/en/images/triggeredbytask.gif b/docs/en/images/triggeredbytask.gif new file mode 100644 index 00000000..bd072f24 Binary files /dev/null and b/docs/en/images/triggeredbytask.gif differ diff --git a/docs/en/images/triggeredbytask.jpg b/docs/en/images/triggeredbytask.jpg new file mode 100644 index 00000000..35f47c27 Binary files /dev/null and b/docs/en/images/triggeredbytask.jpg differ diff --git a/docs/en/images/web_api.gif b/docs/en/images/web_api.gif new file mode 100644 index 00000000..a4e2143f Binary files /dev/null and b/docs/en/images/web_api.gif differ diff --git a/docs/en/images/webhook.gif b/docs/en/images/webhook.gif new file mode 100644 index 00000000..74ae17b0 Binary files /dev/null and b/docs/en/images/webhook.gif differ diff --git a/docs/en/images/webhookexpanded.jpg b/docs/en/images/webhookexpanded.jpg new file mode 100644 index 00000000..7dade5c6 Binary files /dev/null and b/docs/en/images/webhookexpanded.jpg differ diff --git a/docs/en/images/webrequesttask.jpg b/docs/en/images/webrequesttask.jpg new file mode 100644 index 00000000..375d79d3 Binary files /dev/null and b/docs/en/images/webrequesttask.jpg differ diff --git a/docs/en/images/workflow.gif b/docs/en/images/workflow.gif new file mode 100644 index 00000000..e5b793bd Binary files /dev/null and b/docs/en/images/workflow.gif differ diff --git a/docs/en/images/workflow1.jpg b/docs/en/images/workflow1.jpg new file mode 100644 index 00000000..5582de9d Binary files /dev/null and b/docs/en/images/workflow1.jpg differ diff --git a/docs/en/images/workflow2.jpg b/docs/en/images/workflow2.jpg new file mode 100644 index 00000000..1e0da275 Binary files /dev/null and b/docs/en/images/workflow2.jpg differ diff --git a/docs/en/images/workflow3.jpg b/docs/en/images/workflow3.jpg new file mode 100644 index 00000000..141429fe Binary files /dev/null and b/docs/en/images/workflow3.jpg differ diff --git a/docs/en/images/workflow4.jpg b/docs/en/images/workflow4.jpg new file mode 100644 index 00000000..7efdf3d5 Binary files /dev/null and b/docs/en/images/workflow4.jpg differ diff --git a/docs/en/images/workflow5.jpg b/docs/en/images/workflow5.jpg new file mode 100644 index 00000000..9fcef5d7 Binary files /dev/null and b/docs/en/images/workflow5.jpg differ diff --git a/docs/en/images/workflow6.jpg b/docs/en/images/workflow6.jpg new file mode 100644 index 00000000..c02b3693 Binary files /dev/null and b/docs/en/images/workflow6.jpg differ diff --git a/docs/indicators/README.md b/docs/en/indicators/README.md similarity index 99% rename from docs/indicators/README.md rename to docs/en/indicators/README.md index 7038b291..d0d2daf1 100644 --- a/docs/indicators/README.md +++ b/docs/en/indicators/README.md @@ -258,4 +258,4 @@ curl -X DELETE "https://supervisor.theeye.io/indicator/title/${TITLE_INDICATOR}? Please, check out the indicators recipe example. After importing It, fulfill the api-key and then run it, It covers the most common requirements. -Check the [Recipes Documentation](/assets/recipes/) for more details. +Check the [Recipes Documentation](enassets/recipes/) for more details. diff --git a/docs/jobs/README.md b/docs/en/jobs/README.md similarity index 100% rename from docs/jobs/README.md rename to docs/en/jobs/README.md diff --git a/docs/en/monitors/README.md b/docs/en/monitors/README.md new file mode 100644 index 00000000..ef25e370 --- /dev/null +++ b/docs/en/monitors/README.md @@ -0,0 +1,138 @@ +# API for Monitors + +[![theeye.io](../images/logo-theeye-theOeye-logo2.png)](https://theeye.io/en/index.html) + +## API URL for Monitors + +URL: `https://supervisor.theeye.io/monitor?access_token={token}&customer={organization_name}` + +| Method | Path | Description | ACL | +| ----- | ----- | ----- | ----- | +| GET | /monitor | [List Monitors](#example-1) | viewer | +| GET | /monitor | [Search monitor by name](#example-2) | viewer | +| GET | /monitor | [Show bot stats](#example-3) | viewer | +| DELETE | /monitor/${id} | [Delete Monitor](#example-4) | admin | +| POST |/monitor | [Create Web Check Monitor](#example-5) | admin | +| GET | /monitor/${id}| [Get Monitor by Id](#example-6) | viewer | +| GET | /monitor| [Get Monitor by name](#example-7) | viewer | + +### Variables: + **customer**: organization name + + **access token**: menu => settings => credentials => Integration Tokens + +## Examples + + +#### **Example 1** + +#### List monitors: + +```bash +customer=$(echo $THEEYE_ORGANIZATION_NAME | jq -r '.') +token=$THEEYE_ACCESS_TOKEN + + curl -sS "https://supervisor.theeye.io/monitor?access_token=${token}&customer=${customer}" +``` +#### **Example 2** + +##### **Search monitor by name** + +```bash + customer=$(echo $THEEYE_ORGANIZATION_NAME | jq -r '.') + token=$THEEYE_ACCESS_TOKEN + monName=$1 + + curl -sS "https://supervisor.theeye.io/monitor?access_token=${token}&customer=${customer}" | \ + jq -r --arg name "${monName}" '.[] | select(.name==$name) | {"name": .name, "id": .id, "state": .resource.state}' | jq -s '.' +``` +#### **Example 3** + +##### **Show bot stats** + +```bash + customer=$(echo $THEEYE_ORGANIZATION_NAME | jq -r '.') + token=$THEEYE_ACCESS_TOKEN + botName=$1 + + curl -sS "https://supervisor.theeye.io/monitor?access_token=${token}&customer=${customer}" | \ + jq -r --arg name "${botName}" '.[] | select((.name==$name) and (.type=="dstat")) | {"name": .name, "id": .id, "stats": .resource.last_event.data}' | jq -s '.' +``` + +#### **Response example:** + +```json +[ + { + "name": "demo", + "id": "5bb755f42f78660012bdd9af", + "stats": { + "cpu": 3, + "mem": 36.73548113271163, + "cache": 4.689083037753453, + "disk": [ + { + "name": "xvda2", + "value": 84.84461326890819 + } + ] + } + } +] +``` + +#### **Example 4** + +##### **Delete Monitor** +```bash + +customer=$(echo $THEEYE_ORGANIZATION_NAME | jq -r '.') +token=$THEEYE_ACCESS_TOKEN +id_monitor=$1 + +curl -X DELETE "https://supervisor.theeye.io/monitor/${id_monitor}?access_token=${token}&customer=${customer}" +``` + + +#### **Example 5** + +##### **Create Web Check Monitor** + +```bash +customer=$(echo $THEEYE_ORGANIZATION_NAME | jq -r '.') +token=$THEEYE_ACCESS_TOKEN +host_id=$1 +url=$2 +monitorName=$3 + +curl -sS -X POST "https://supervisor.theeye.io/monitor?access_token=${token}&customer=${customer}&host_id=${host_id}" \ +--header 'Content-Type: application/json' \ +--data "{\"name\":\"${monitorName}\",\"host_id\":\"${host_id}\",\"url\":\"${url}\",\"timeout\":\"5000\",\"looptime\":\"15000\",\"type\":\"scraper\",\"status_code\":\"200\",\"_type\":\"ScraperMonitor\"}" +``` +#### **Example 6** + +##### **Get Monitor by Id** + +```bash +customer=$(echo $THEEYE_ORGANIZATION_NAME | jq -r '.') token=$THEEYE_ACCESS_TOKEN +id_monitor=$1 + + +curl -sS -X GET "https://supervisor.theeye.io/monitor/${id_monitor}?access_token=${token}&customer=${customer}" +``` +#### **Example 7** + +##### **Get Monitor by name** + +```bash +customer=$(echo $THEEYE_ORGANIZATION_NAME | jq -r '.') +token=$THEEYE_ACCESS_TOKEN +nameMonitor=$1 + + +curl -sS -X GET "https://supervisor.theeye.io/monitor?access_token=${token}&where\[name\]=${nameMonitor}" +``` + + + + diff --git a/docs/en/sync/README.md b/docs/en/sync/README.md new file mode 100644 index 00000000..242039cb --- /dev/null +++ b/docs/en/sync/README.md @@ -0,0 +1,197 @@ +[![theeye.io](../../images/logo-theeye-theOeye-logo2.png)](https://theeye.io/index.html) + +# Sync API + +## URL + +**https://sync.theeye.io** + +____ + +Tasks execution in TheEye is asynchronous by nature. This means, that task will get executed and then continue in background an the time it takes to complete varies. Usually, we do not need to wait the result and we can check it later. + +But there are cases when we need to invoke the task and we want to wait the result. This is very common when connecting apis, using task with interfaces that requires user interaction and many other escenarios. + +This can be achived using the API in sync mode. The only restriction is the task execution timeout. A recommended timeout would be between 10 to 30 seconds maximum. Most of the web client will abort the request near the 60 seconds. Clients behaviour can be configured and changed but experience tells us that it is not recommended, unless you really need it. + +___ + + +## Paths + +| Method | Path | Description | ACL | +| ---- | ----| ----| ----| +| POST | /${customer}/task/${id}/job | [Run task](#waiting-output) | user | + + +## Arguments + + +| Name | Values | Description | +| ---- | ---- | ---- | +| result | empty/null. is ignored | Result is another field stored with the job execution data in the database. This includes the execution log, the output, the lastline. | +| full | empty/null. is ignored | This is the full job document. This is the same value that can be obtained doing a GET request to the jobs api | +| parse | empty or a Number/Integer > 0 | The output of a job is always stored in the database as an array of Task Arguments strings. The parse option will use the index number 0 of the output and parse it as JSON. In some cases you might need to return a specific index of the output array. Using parse, set it to the a number from 0 to N, representing the index of the output array. If the index is not present or if it is unreadable the raw output will be returned | + + +## Response + +By default the sync api will respond with the final output of the task execution. when a job finishes the output value is parsed and then stored withing the job document in the output field. + +| State | HTTP Status Code | +| ---- | ---- | +| success | 200 | +| failure | 500 | + + +### NOTES + +* Single **Task execution** is supported. Workflows execution is **NOT Possible** at this moment. + +______ + + +## Examples + +### Waiting output + +```bash + +customer="" +taskId="" +token="" + +curl -s -X POST "https://sync.theeye.io/${customer}/task/${taskId}/job?access_token=${token}" | jq .output + + +``` + +### sample failure + + +```bash + +curl -i -X POST 'https://sync.theeye.io/${customer_id}/task/${task_id}/job?access_token=${token}' \ + --header 'content-type: application/json' \ + --data '{"task_arguments":[200]}' + +``` + + +```http + +HTTP/1.1 500 Internal Server Error +X-Powered-By: Express +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET,PUT,PATCH,POST,DELETE,OPTIONS +Access-Control-Allow-Credentials: true +Access-Control-Allow-Headers: Origin, Accept, User-Agent, Accept-Charset, Cache-Control, Accept-Encoding, Content-Type, Authorization, Content-Length, X-Requested-With +Content-Type: application/json; charset=utf-8 +Content-Length: 135 +ETag: W/"87-+Fzdxc2Q7NsFIfhclF3lcqgSScY" +Date: Fri, 28 Jan 2022 16:59:54 GMT +Connection: keep-alive +Keep-Alive: timeout=5 + +["{\"message\":\"Validation Error. Invalid Argument Value\",\"statusCode\":418,\"name\":\"ClientError\",\"code\":\"\",\"status\":418}"] + + +``` + +### sample success + + +```bash + +curl -i -X POST 'https://sync.theeye.io/${customer_id}/task/${task_id}/job?access_token=${token}' \ + --header 'content-type: application/json' \ + --data '{"task_arguments":[100]}' + +``` + +```http + +HTTP/1.1 200 OK +X-Powered-By: Express +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET,PUT,PATCH,POST,DELETE,OPTIONS +Access-Control-Allow-Credentials: true +Access-Control-Allow-Headers: Origin, Accept, User-Agent, Accept-Charset, Cache-Control, Accept-Encoding, Content-Type, Authorization, Content-Length, X-Requested-With +Content-Type: application/json; charset=utf-8 +Content-Length: 62 +ETag: W/"3e-Earn8PE7JwarkhTciq4Sn4inI3g" +Date: Fri, 28 Jan 2022 17:00:22 GMT +Connection: keep-alive +Keep-Alive: timeout=5 + +["{\"name\":\"tomer\",\"date\":\"2022-01-28T17:00:22.676Z\"}"] + +``` + + +### sample success using parse + +[Download and Import this task](ensync/Rest_API_Response.json ":ignore") + + +Get the ID and replace in the requests below + +```bash + +curl -i -X POST 'https://sync.theeye.io/${customer_id}/task/${task_id}/job?parse&access_token=${token}' \ + --header 'content-type: application/json' \ + --data '{"task_arguments":[100]}' + +``` + + +```http + +HTTP/1.1 200 OK +X-Powered-By: Express +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET,PUT,PATCH,POST,DELETE,OPTIONS +Access-Control-Allow-Credentials: true +Access-Control-Allow-Headers: Origin, Accept, User-Agent, Accept-Charset, Cache-Control, Accept-Encoding, Content-Type, Authorization, Content-Length, X-Requested-With +Content-Type: application/json; charset=utf-8 +Content-Length: 50 +ETag: W/"32-QGrCXrCY2sEcc1V/fL6omhdvPKY" +Date: Fri, 28 Jan 2022 16:26:41 GMT +Connection: keep-alive +Keep-Alive: timeout=5 + +{"name":"tomer","date":"2022-01-28T16:26:41.201Z"} + +``` + +### sample failure using parse + + +```bash + +curl -i -X POST 'https://sync.theeye.io/${customer_id}/task/${task_id}/job?parse&access_token=${token}' \ + --header 'content-type: application/json' \ + --data '{"task_arguments":[200]}' + +``` + + +```http + +HTTP/1.1 418 I'm a Teapot +X-Powered-By: Express +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET,PUT,PATCH,POST,DELETE,OPTIONS +Access-Control-Allow-Credentials: true +Access-Control-Allow-Headers: Origin, Accept, User-Agent, Accept-Charset, Cache-Control, Accept-Encoding, Content-Type, Authorization, Content-Length, X-Requested-With +Content-Type: application/json; charset=utf-8 +Content-Length: 115 +ETag: W/"73-FBmPIgGdDNzn6NM27joxlSUMWp4" +Date: Fri, 28 Jan 2022 16:56:47 GMT +Connection: keep-alive +Keep-Alive: timeout=5 + +{"message":"Validation Error. Invalid Argument Value","statusCode":418,"name":"ClientError","code":"","status":418} + +``` + diff --git a/docs/en/sync/Rest_API_Response.json b/docs/en/sync/Rest_API_Response.json new file mode 100644 index 00000000..25787983 --- /dev/null +++ b/docs/en/sync/Rest_API_Response.json @@ -0,0 +1 @@ +{"task":{"order":0,"enable":true,"type":"script","public":false,"tags":[],"grace_time":0,"task_arguments":[{"id":1,"order":0,"type":"input","label":"number","value":"","help":"","readonly":false,"required":true,"multiple":false,"masked":false,"charsmin":0,"charsmax":0,"charset":null,"pattern":"","options":[]}],"arguments_type":"legacy","output_parameters":[],"register_body":false,"execution_count":83,"multitasking":true,"show_result":false,"assigned_users":[],"user_inputs":false,"user_inputs_members":[],"empty_viewers":false,"cancellable":true,"autoremove_completed_jobs_limit":5,"script_arguments":[{"id":1,"order":0,"type":"input","label":"number","value":"","help":"","readonly":false,"required":true,"multiple":false,"masked":false,"charsmin":0,"charsmax":0,"charset":null,"pattern":"","options":[]}],"logging":false,"_type":"ScriptTask","creation_date":"2022-01-28T13:01:43.355Z","last_update":"2022-01-28T16:56:46.292Z","env":{"NODE_ENV":""},"name":"Rest API Response","description":"","timeout":600000,"allows_dynamic_settings":false,"script_runas":"node %script%","template":null,"template_id":null,"source_model_id":"61f3e937c38201da80f96c27"},"file":{"order":0,"filename":"api.js","keyname":"api.js[ts:1643388995376]","mimetype":"text/javascript","extension":"js","size":2079,"description":"","md5":"824a8455060c66ebce1408efb52652dd","public":false,"tags":[],"source_model_id":"61f3e92cc38201da80f96c26","data":"Ly8gZXJyb3IgYW5kIG91dHB1dCBoYW5kbGVycyBtdXN0IGdvIGZpcnN0LgoKLyoqCiAqIEBwYXJhbSB7T2JqZWN0fQogKiBAcHJvcCB7TWl4ZWR9IGRhdGEKICogQHByb3Age0FycmF5fSBjb21wb25lbnRzCiAqIEBwcm9wIHtPYmplY3R9IG5leHQKICovCmNvbnN0IHN1Y2Nlc3NPdXRwdXQgPSAoeyBkYXRhLCBjb21wb25lbnRzLCBuZXh0IH0pID0+IHsKICAvLyBodHRwczovL2RvY3VtZW50YXRpb24udGhlZXllLmlvL2NvcmUtY29uY2VwdHMvc2NyaXB0cy8jcGFzc2luZy1hcmd1bWVudHMtaW4td29ya2Zsb3cKICBjb25zdCBvdXRwdXQgPSB7CiAgICBzdGF0ZTogInN1Y2Nlc3MiLAogICAgZGF0YSwKICAgIGNvbXBvbmVudHMsIC8vIGh0dHBzOi8vZG9jdW1lbnRhdGlvbi50aGVleWUuaW8vY29yZS1jb25jZXB0cy90YXNrcy9zY3JpcHRfdHlwZS8jY29tcG9uZW50cwogICAgbmV4dAogIH0KICBjb25zb2xlLmxvZyggSlNPTi5zdHJpbmdpZnkob3V0cHV0KSApCiAgcHJvY2Vzcy5leGl0KDApCn0KCi8qKgogKiBAcGFyYW0ge0Vycm9yfSBlcnIKICovCmNvbnN0IGZhaWx1cmVPdXRwdXQgPSAoZXJyKSA9PiB7CiAgY29uc29sZS5lcnJvcihlcnIpCiAgY29uc3Qgb3V0cHV0ID0gewogICAgc3RhdGU6ICJmYWlsdXJlIiwKICAgIGRhdGE6IGVycgogIH0KICBjb25zb2xlLmVycm9yKCBKU09OLnN0cmluZ2lmeShvdXRwdXQpICkKICBwcm9jZXNzLmV4aXQoMSkKfQoKcHJvY2Vzcy5vbigndW5oYW5kbGVkUmVqZWN0aW9uJywgKHJlYXNvbiwgcCkgPT4gewogIGNvbnNvbGUuZXJyb3IocmVhc29uLCAnVW5oYW5kbGVkIFJlamVjdGlvbiBhdCBQcm9taXNlJywgcCkKICBmYWlsdXJlT3V0cHV0KHJlYXNvbikKfSkKCnByb2Nlc3Mub24oJ3VuY2F1Z2h0RXhjZXB0aW9uJywgZXJyID0+IHsKICBjb25zb2xlLmVycm9yKGVyciwgJ1VuY2F1Z2h0IEV4Y2VwdGlvbiB0aHJvd24nKQogIGZhaWx1cmVPdXRwdXQoZXJyKQp9KQoKLy8gTm9kZUpzIGJvaWxlcnBsYXRlCmNvbnN0IG1haW4gPSBhc3luYyAoKSA9PiB7CiAgY29uc3QgYXJncyA9IHByb2Nlc3MuYXJndi5zbGljZSgyKQoKICBpZiAoYXJnc1swXSA+IDEwMCkgewogICAgdGhyb3cgbmV3IENsaWVudEVycm9yKCdWYWxpZGF0aW9uIEVycm9yLiBJbnZhbGlkIEFyZ3VtZW50IFZhbHVlJywgeyBzdGF0dXNDb2RlOiA0MTggfSkKICB9CgogIGNvbnN0IHJlc3VsdCA9IHsKICAgIGRhdGE6IHsKICAgICAgbmFtZTogInRvbWVyIiwKICAgICAgZGF0ZTogbmV3IERhdGUoKQogICAgfSwKICAgIGNvbXBvbmVudHM6IHsgInBvcHVwIjogIkhpIFdvcmxkISIgfSwKICAgIG5leHQ6IHt9CiAgfQoKICAvLyBhZGQgeW91ciBjb2RlIGhlcmUuCgogIHJldHVybiByZXN1bHQKfQoKY2xhc3MgQ2xpZW50RXJyb3IgZXh0ZW5kcyBFcnJvciB7CiAgY29uc3RydWN0b3IgKG1lc3NhZ2UsIG9wdGlvbnMpIHsKICAgIHN1cGVyKG1lc3NhZ2UgfHwgJ0ludmFsaWQgUmVxdWVzdCcpCiAgICBvcHRpb25zfHwob3B0aW9ucz17fSkKICAgIE9iamVjdC5hc3NpZ24odGhpcywgb3B0aW9ucykKICAgIHRoaXMubmFtZSA9IHRoaXMuY29uc3RydWN0b3IubmFtZQogICAgdGhpcy5jb2RlID0gb3B0aW9ucy5jb2RlIHx8ICcnCiAgICB0aGlzLnN0YXR1cyA9IG9wdGlvbnMuc3RhdHVzQ29kZSB8fCA0MDAKICB9CiAgCiAgdG9KU09OICgpIHsKICAgIGxldCBhbHQgPSB7fQogICAgbGV0IHN0b3JlS2V5ID0gZnVuY3Rpb24gKGtleSkgewogICAgICBpZiAoa2V5ID09PSAnc3RhY2snKSB7CiAgICAgICAgaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSAncHJvZHVjdGlvbicpIHsKICAgICAgICAgIGFsdFtrZXldID0gdGhpc1trZXldCiAgICAgICAgfQogICAgICB9IGVsc2UgewogICAgICAgIGFsdFtrZXldID0gdGhpc1trZXldCiAgICAgIH0KICAgIH0KICAgIE9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKHRoaXMpLmZvckVhY2goc3RvcmVLZXksIHRoaXMpCiAgICByZXR1cm4gYWx0CiAgfQp9CgoKCi8vIGludm9rZSBtYWluIGFuZCBjYXB0dXJlIHJlc3VsdCBvdXRwdXQKbWFpbigpLnRoZW4oc3VjY2Vzc091dHB1dCkuY2F0Y2goZmFpbHVyZU91dHB1dCkK"}} \ No newline at end of file diff --git a/docs/en/tasks/README.md b/docs/en/tasks/README.md new file mode 100644 index 00000000..e90068b8 --- /dev/null +++ b/docs/en/tasks/README.md @@ -0,0 +1,250 @@ +[![theeye.io](../images/logo-theeye-theOeye-logo2.png)](https://theeye.io/en/index.html) + +# Tasks API + +____ + +## API Paths + +| Method | Path | Description | ACL | +| ----- | ----- | ----- | ----- | +| GET | /${customer}/task | [List all](#example-1) | viewer | +| | | [List and timeout](#example-3) | viewer | +| GET | /${customer}/task/${id} | [Get by id](#example-2) | viewer | +| DELETE | /${customer}/task/${id} | Remove task | admin | +| GET | /${customer}/task/:task/recipe | Get task recipe | admin | +| GET | /${customer}/task/import | Create from recipe | admin | +| GET | /${customer}/task/:task/credentials | Get task secret | admin | +| POST | /${customer}/task/${id}/job | Run task | user | +| POST | /${customer}/task/${id}/secret/${task_secret_key}/job | [Using task secret key](#example-4) | anonymous | +| DELETE | /${customer}/task/${id}/job | Empty jobs queue | admin | + +### NOTES + +* _customer_ (REQUIRED) + + Can be included in the body as "customer" + +* _access_token_ (REQUIRED) + + Can be provided vía Authorization header \( Authorization: Bearer ${token} \) + +----- + + +## Model Properties + +| Property Name | UI Name | Type | Default | Description | +| ----- | ----- | ----- | | ----- | +| name | Name | string | | name your task | +| host_id | Bots | string | | select the host where the script will run | +| script_id | Script | string | | select the script to be executed by the task | +| tags | Tags | strings array | | tag your task so you can find quickly through the application. | +| task_arguments | Task Arguments | array | | If the script played by the task is meant to receive parameters you can set them from here. Mind the order as it will be used by the script. _Fixed_, _options_, and _input_ arguments are allowed. _Input_ and _options_ arguments will be asked to the user for execution. _Fixed_ arguments will not be displayed to the user at execution time. | +| run_as | Run As | string | | write down any extra command or argument needed to run the script. Windows users must declare here which interpreter to use. Linux users could prepend sudo | +| description | Description | text | | describe your task. What does it do, what's the expected output after execution | +| acls | ACL's | array | | select who can view your task \(what can be done with the task depends on the user role\) | +| triggers | Triggered by | array | | If the task is part of a workflow, select what triggers the task. The task will be triggered by the resource you selected here. | +| grace_time | Trigger on-hold time | number | | enter the time period TheEye should wait before running the task. _No wait / Cancelation_ can be selected which means the task will run inmediately after triggered. \(only applicable for triggered tasks\). **To cancel the task execution during the grace period, go to tasks panel, expand the task and delete the schedule created by the trigger.** | +| timeout | Execution Timeout | number | 600 | This is the number of seconds the Bot will wait for the script to complete the execution. If the timeout is exceeded the Bot will try to terminate(kill) the script, sending SIGTERM/SIGKILL signal | +| multitasking | Multitasking | boolean | | enable or disable parallel execution of the task. When this is enable assigned bot will be able to run multiple instances of the Job at same time. this is important to check when running DesktopBots | +| env | Environment (env) | string | | Define extra environment variables that will be present during script execution | + +### NOTES + +* _timeout_ + + The default execution timeout for tasks is 10 minutes. + + Now it's not possible to change the timeout via API. + + To modify the timeout for a task use the Web Interface. + +----- + +## Running tasks + +For a **Task** to run, internally, a new **Job** is created and added to the queue. If you want to run a **task** you only need to create a **Job** manually and supply the task ID \(and task options\) you want to run. + +Note that in this example we are executing a task with no arguments, task_arguments is an empty array. +To execute a task with arguments, provide the list of ordered arguments in the "task_arguments" parameter. +Each argument must be a valid JSON escaped string. + +This is easily done with a POST request to the Job endpoint API. + +There are two methods available. + +### Task and Workflow execution payload via API + +When creating Task Jobs via API you will have to provide the Task ID and the Task Arguments. + +```javascript +{ + // (required) + task: "task id", + // (required only if task has arguments) + task_arguments: [] +} +``` + +### Using task secret key. Integration Feature \(recommended\) + +All tasks and workflows have a **secret key** which can be used to invoke them directly via API. +The secret key provides access to the task it belongs **and only to that task**. +**Secret keys** can be revoked any time by just changing them, which makes this the preferred method for it's implicity and security. + +----- + +## Examples + + +### **Example 1** +### Get all + +*Resquest* + +```bash +customer=$THEEYE_ORGANIZATION_NAME + +curl -sS "https://supervisor.theeye.io/${customer}/task?access_token=$THEEYE_TOKEN" +``` + +### **Example 2** +### Get by id + +*Request* + +```bash +customer=$THEEYE_ORGANIZATION_NAME +task_id=$(echo $THEEYE_JOB | jq -r '.task_id') +echo "task id: ${task_id}" + +result=$(curl -sS "https://supervisor.theeye.io/${customer}/task/${task_id}?access_token=${THEEYE_TOKEN}") + +echo $result | jq -c '. | {"name": .name, "id": .id, "hostname": .hostname}' +``` + +*Response* + +Returns a json array with tasks, id and hostname: +```json +[ + { + "name": "Get IP Address", + "id": "5b1c65ee3c32bb1100c2920a", + "hostname": "Apache3" + }, + { + "name": "Get IP Address", + "id": "5b1c65ee3c32bb1100c29210", + "hostname": "Apache1" + }, + { + "name": "Get IP Address", + "id": "5b1c65efd421031000213bb8", + "hostname": "Apache4" + }, + { + "name": "Get IP Address", + "id": "5b1c65efd421031000213bc6", + "hostname": "Apache2" + } +] +``` + +### **Example 3** +### List and timeout + +(Timeout = null) means that the timeout is set to default (10 minutes). + +```bash +#!/bin/bash + +customer=$1 +access_token=$THEEYE_TOKEN +supervisor=$2 +if [ $2 == "" ]; then supervisor='https://supervisor.theeye.io' ; fi +if [ $# -ne 2 ]; then echo "missing parameters" ; exit ; fi + +data=$(curl -s ${supervisor}/${customer}/task?access_token=${access_token}) + +echo "${data}" | jq -j '.[] | "id: ", .id, "\ttask: ", .name, "\ttimeout: ", .timeout, "\n"' +``` + + +### **Example 4** +### Execute using secret key + +```bash +task_id=$TASK_ID +task_secret_key=$TASK_SECRET +customer=$(echo $THEEYE_ORGANIZATION_NAME | jq -r '.') + +curl -i -sS \ + --request POST \ + --header "Accept: application/json" \ + --header "Content-Type: application/json" \ + --data-urlencode "customer = ${customer}" \ + --data-urlencode "task = ${task_id}" \ + --url "https://supervisor.theeye.io/job/secret/${task_secret_key}" +``` + +### **Example 5** +### HTML Button + +This technique could be combined with an HTML form to generate an action button. +This is very handy when it is needed to perform actions from email bodies or static web pages. + +```html + +Sample approval request + + + + +``` + +### **Example 6** +### API integration tokens + +Integration Tokens can be obtained only by admin users. + +

Integration Tokens has full admin privileges. Keep it safe

+ +Accessing to the web interfaz *Menu > Settings > Credentials > Integration Tokens*. + + +```bash +task_id=$TASK_ID +access_token=$ACCESS_TOKEN +customer=$(echo $THEEYE_ORGANIZATION_NAME | jq -r '.') + + +curl -X POST \ + -H "Accept: application/json" \ + -H "Content-Type: application/json" \ + -d "{\"task_arguments\":[]}" \ + "https://supervisor.theeye.io/job?access_token=${access_token}&customer=${customer}&task=${task_id}" + +``` + +The API response is a the created job. We can save the job id and use it later to query the job status. diff --git a/docs/en/tasks/arguments.md b/docs/en/tasks/arguments.md new file mode 100644 index 00000000..ffaf3f37 --- /dev/null +++ b/docs/en/tasks/arguments.md @@ -0,0 +1,111 @@ +[![theeye.io](../images/logo-theeye-theOeye-logo2.png)](https://theeye.io/en/index.html) + +# Tasks Arguments + +_____ + +## Task and Workflows. API execution + +There are alternatives to directly execute tasks and workflows vía API. + +Check the following Documentation Sections + + +[Run Task and Workflow using Integration Secret (recomended)](entasks/#using-task-secret-key-integration-feature-40recommended41) + +[Run Task and Workflow using Integration Token (beta)](entasks/#api-integration-tokens) + +___ + +## Providing Arguments + +To execute a task via Api you must provide the values for every task argument. + + +### application/json + +#### Alternative 1 + +```shell +secret=$SECRET_ID +task=$TASK_ID +customer=$(echo $THEEYE_ORGANIZATION_NAME | jq -r '.') + +curl -i -sS \ + --request POST \ + --url "https://supervisor.theeye.io/job/secret/${secret}?customer=${customer}&task=${task}" \ + --header 'Content-Type: application/json' \ + --data '{"task_arguments":["arg1","arg2"]}' + +``` + +#### Alternative 2 + +The full request body will must be an array. +Each index of the array will be mapped in the provided order with the task arguments. + + +```shell +secret=$SECRET_ID +task=$TASK_ID +customer=$(echo $THEEYE_ORGANIZATION_NAME | jq -r '.') + +curl -i -sS \ + --request POST \ + --url "https://supervisor.theeye.io/${customer}/task/${task}/secret/${secret}/job" \ + --header 'Content-Type: application/json' \ + --data '["",{"prop":"value"},[1,2,3],0,null,"hola",""]' + +``` + +### application/x-www-form-urlencoded + +```shell +secret=$SECRET_ID +task=$TASK_ID +customer=$(echo $THEEYE_ORGANIZATION_NAME | jq -r '.') + +curl -i -sS \ + --request POST \ + --url "https://supervisor.theeye.io/job/secret/${secret}?customer=${customer}&task=${task}" \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode task_arguments="arg1" \ + --data-urlencode task_arguments="arg2" + --data-urlencode task_arguments="arg3" + +``` + +### querystring + +#### Alternative 1 + +```shell + +secret=$SECRET_ID +customer=$(echo $THEEYE_ORGANIZATION_NAME | jq -r '.') +task=$TASK_ID + +curl -i -sS \ + --request POST \ + --url "https://supervisor.theeye.io/job/secret/${secret}?customer=${customer}&task=${task}&task_arguments\[\]=arg1&task_arguments\[\]=arg2" + +``` + +#### Alternative 2 + + +```shell + +secret=$SECRET_ID +customer=$(echo $THEEYE_ORGANIZATION_NAME | jq -r '.') +task=$TASK_ID + +curl -i -sS \ + --request POST \ + --url "https://supervisor.theeye.io/job/secret/${secret}" \ + --data-urlencode "task=${task}" \ + --data-urlencode "customer=${customer}" \ + --data-urlencode "task_arguments[]=${arg1}" \ + --data-urlencode "task_arguments[]=${arg2}" + +``` diff --git a/docs/webhooks/README.md b/docs/en/webhooks/README.md similarity index 98% rename from docs/webhooks/README.md rename to docs/en/webhooks/README.md index ac3feb85..bedeb380 100644 --- a/docs/webhooks/README.md +++ b/docs/en/webhooks/README.md @@ -25,7 +25,7 @@ Then, simply removing the Webhook, you can revoke the remote access to the Task. * Base Path `/${customer}/webhook?access_token=${token}` -* [Bearer authentication required](/api/auth) +* [Bearer authentication required](enapi/auth) | Method | Path | Description | ACL | | ----- | ----- | ----- | ----- | diff --git a/docs/index.html b/docs/index.html index 0da93b46..a9bb9bb8 100644 --- a/docs/index.html +++ b/docs/index.html @@ -6,7 +6,12 @@ - +
@@ -14,12 +19,18 @@ window.$docsify = { name: 'TheEye Documentation', repo: 'https://github.com/theeye-io-team/theeye-supervisor', + loadNavbar: true, loadSidebar: true, - subMaxLevel: 2, + subMaxLevel: 3, auto2top: true, search: 'auto', + fallbackLanguages: ['en'], logo: 'logo-theeye-theOeye.png', - themeColor: "#004E7A" + themeColor: "#004E7A", + tabs: { + theme: 'material', + tabHeadings: true + } } @@ -27,5 +38,12 @@ + + + + diff --git a/docs/monitors/README.md b/docs/monitors/README.md index ef25e370..0dd56a5d 100644 --- a/docs/monitors/README.md +++ b/docs/monitors/README.md @@ -1,102 +1,466 @@ -# API for Monitors +# API para Monitores [![theeye.io](../images/logo-theeye-theOeye-logo2.png)](https://theeye.io/en/index.html) -## API URL for Monitors +## URL de la API para Monitores + +```javascript +`https://supervisor.theeye.io/monitor?access_token=${THEEYE_ACCESS_TOKEN}&customer=${THEEYE_ORGANIZATION_NAME}` +``` + +| Method | Path | Description | ACL | +| ------ | -------------- | ---------------------------------------------- | ------ | +| GET | /monitor | [Enlistar Monitores](#ejemplo-1) | viewer | +| GET | /monitor/${id} | [Mostrar un Monitor por su ID](#ejemplo-5) | viewer | +| POST | /monitor | [Crea un Monitor](#ejemplo-4) | admin | +| DELETE | /monitor/${id} | [Elimina el Monitor](#ejemplo-3) | admin | -URL: `https://supervisor.theeye.io/monitor?access_token={token}&customer={organization_name}` -| Method | Path | Description | ACL | -| ----- | ----- | ----- | ----- | -| GET | /monitor | [List Monitors](#example-1) | viewer | -| GET | /monitor | [Search monitor by name](#example-2) | viewer | -| GET | /monitor | [Show bot stats](#example-3) | viewer | -| DELETE | /monitor/${id} | [Delete Monitor](#example-4) | admin | -| POST |/monitor | [Create Web Check Monitor](#example-5) | admin | -| GET | /monitor/${id}| [Get Monitor by Id](#example-6) | viewer | -| GET | /monitor| [Get Monitor by name](#example-7) | viewer | ### Variables: - **customer**: organization name + * **customer**: Nombre de la organización. + * **access token**: Clave de integración. [Más información](/auth#identificadores-de-integración-integration-tokens) + +## Ejemplos + +### **Ejemplo 1** + +#### Enlistar Monitores - **access token**: menu => settings => credentials => Integration Tokens +En este ejemplo enviaremos un GET request que nos devolverá una lista de todos los monitores de una organización. -## Examples + +##### **Bash** -#### **Example 1** +##### Nota: -#### List monitors: +> Se asume que están declaradas las variables de entorno `THEEYE_ORGANIZATION_NAME` como el nombre de la organización y `THEEYE_ACCESS_TOKEN` como la Secret Key de la tarea ```bash -customer=$(echo $THEEYE_ORGANIZATION_NAME | jq -r '.') -token=$THEEYE_ACCESS_TOKEN +#!/bin/bash +curl -sS "https://supervisor.theeye.io/monitor?access_token=${THEEYE_ACCESS_TOKEN}&customer=${THEEYE_ORGANIZATION_NAME}" +``` + +##### **Javascript** + +##### Nota: + +> Se asume que están declaradas las variables `window.THEEYE_ORGANIZATION_NAME` como el nombre de la organización y `window.THEEYE_TOKEN` como la Secret Key de la tarea - curl -sS "https://supervisor.theeye.io/monitor?access_token=${token}&customer=${customer}" +```javascript +let xhr = new XMLHttpRequest(); +xhr.open('GET', `https://supervisor.theeye.io/monitor?access_token=${window.THEEYE_ACCESS_TOKEN}&customer=${window.THEEYE_ORGANIZATION_NAME}`); + +xhr.onload = () => { + console.log(JSON.parse(xhr.response)) +} + +xhr.send(null) ``` -#### **Example 2** -##### **Search monitor by name** +##### **Node.js** + +##### Nota: + +> Se asume que están declaradas las variables de entorno `THEEYE_ORGANIZATION_NAME` como el nombre de la organización y `THEEYE_ACCESS_TOKEN` como la Secret Key de la tarea + +```javascript +const https = require('https') + +const options = { + host: 'supervisor.theeye.io', + path: `/monitor?access_token=${process.env.THEEYE_ACCESS_TOKEN}&customer=${process.env.THEEYE_ORGANIZATION_NAME}`, + method: 'GET' +} + +const req = https.request(options, res => { + let data = '' + + res.on('data', d => { + data = data + d + }) + + res.on('end', () => { + console.log(JSON.parse(data)) + }) +}) + +req.on('error', error => { + console.error(error) +}) + +req.end() +``` + +##### **Python** + +##### Nota: + +> Se asume que están declaradas las variables de entorno `THEEYE_ORGANIZATION_NAME` como el nombre de la organización y `THEEYE_ACCESS_TOKEN` como la Secret Key de la tarea +> +> También se asume que está instalada la librería [`requests`](https://pypi.python.org/pypi/requests/), de no tenerla puede instalarla usando `pip` + +```python +import os +import requests + +url = "https://supervisor.theeye.io/monitor" + +params = { + "access_token": os.getenv("THEEYE_ACCESS_TOKEN"), + "customer": os.getenv("THEEYE_ORGANIZATION_NAME") +} + +r = requests.get(url, params) + +print(r.json()) +``` + + + +#### **Ejemplo 2** + +##### **Filtrar lista de monitores** + +Igual al ejemplo anterior, pero podemos filtrar la lista usando el argumento `where`. En el mismo contiene un parámetro y su respectivo valor, y dicho parámetro puede ser cualquiera de las propiedades del modelo de Monitor. Esto devuelve una lista con todos los monitores que coinciden con el filtro. En este caso, queremos buscar solo los Monitores cuyo `state` sea `normal`. + + + +##### **Bash** + +##### Nota: + +> Se asume que están declaradas las variables de entorno `THEEYE_ORGANIZATION_NAME` como el nombre de la organización y `THEEYE_ACCESS_TOKEN` como la Secret Key de la tarea +> +> En el ejemplo definiremos el parámetro por el que queremos filtrar en la variable `key`, y el valor esperado en la variable `value` ```bash - customer=$(echo $THEEYE_ORGANIZATION_NAME | jq -r '.') - token=$THEEYE_ACCESS_TOKEN - monName=$1 +#!/bin/bash +key="state" +value="normal" - curl -sS "https://supervisor.theeye.io/monitor?access_token=${token}&customer=${customer}" | \ - jq -r --arg name "${monName}" '.[] | select(.name==$name) | {"name": .name, "id": .id, "state": .resource.state}' | jq -s '.' +curl -sS "https://supervisor.theeye.io/monitor?access_token=${THEEYE_ACCESS_TOKEN}&customer=${THEEYE_ORGANIZATION_NAME}&where\[${key}\]=${value}" ``` -#### **Example 3** -##### **Show bot stats** +##### **Javascript** + +##### Nota: + +> Se asume que están declaradas las variables `window.THEEYE_ORGANIZATION_NAME` como el nombre de la organización y `window.THEEYE_TOKEN` como la Secret Key de la tarea +> +> En el ejemplo definiremos el parámetro por el que queremos filtrar en la variable `key`, y el valor esperado en la variable `value` + +```javascript +const key = "state"; +const value = "normal"; + +let xhr = new XMLHttpRequest(); +xhr.open('GET', `https://supervisor.theeye.io/monitor?access_token=${window.THEEYE_ACCESS_TOKEN}&customer=${window.THEEYE_ORGANIZATION_NAME}&where\[${key}\]=${value}`); + +xhr.onload = () => { + console.log(JSON.parse(xhr.response)) +} + +xhr.send(null) +``` + +##### **Node.js** + +##### Nota: + +> Se asume que están declaradas las variables de entorno `THEEYE_ORGANIZATION_NAME` como el nombre de la organización y `THEEYE_ACCESS_TOKEN` como la Secret Key de la tarea +> +> En el ejemplo definiremos el parámetro por el que queremos filtrar en la variable `key`, y el valor esperado en la variable `value`. + +```javascript +const https = require('https') + +const key = "state"; +const value = "normal"; + +const options = { + host: 'supervisor.theeye.io', + path: `/monitor?access_token=${process.env.THEEYE_ACCESS_TOKEN}&customer=${process.env.THEEYE_ORGANIZATION_NAME}&where\[${key}\]=${value}`, + method: 'GET' +} + +const req = https.request(options, res => { + let data = '' + + res.on('data', d => { + data = data + d + }) + + res.on('end', () => { + console.log(JSON.parse(data)) + }) +}) + +req.on('error', error => { + console.error(error) +}) + +req.end() +``` + +##### **Python** + +##### Nota: + +> Se asume que están declaradas las variables de entorno `THEEYE_ORGANIZATION_NAME` como el nombre de la organización y `THEEYE_ACCESS_TOKEN` como la Secret Key de la tarea +> +> También se asume que está instalada la librería [`requests`](https://pypi.python.org/pypi/requests/), de no tenerla puede instalarla usando `pip` +> +> En el ejemplo definiremos el parámetro por el que queremos filtrar en la variable `key`, y el valor esperado en la variable `value` + +```python +import os +import requests + +key = "state" +value = "normal" + +url = "https://supervisor.theeye.io/monitor" + +params = { + "access_token": os.getenv("THEEYE_ACCESS_TOKEN"), + "customer": os.getenv("THEEYE_ORGANIZATION_NAME"), + "where\[" + key + "\]" : value +} + +r = requests.get(url, params) + +print(r.json()) +``` + + + +#### **Ejemplo 3** + +##### **Mostrar un monitor por su ID** + +En este ejemplo enviaremos un GET request que nos devolverá el Monitor asosciado al ID provisto en la URL + + + +##### **Bash** + +##### Nota: + +> Se asume que están declaradas las variables de entorno `THEEYE_ORGANIZATION_NAME` como el nombre de la organización y `THEEYE_ACCESS_TOKEN` como la Secret Key de la tarea ```bash - customer=$(echo $THEEYE_ORGANIZATION_NAME | jq -r '.') - token=$THEEYE_ACCESS_TOKEN - botName=$1 - - curl -sS "https://supervisor.theeye.io/monitor?access_token=${token}&customer=${customer}" | \ - jq -r --arg name "${botName}" '.[] | select((.name==$name) and (.type=="dstat")) | {"name": .name, "id": .id, "stats": .resource.last_event.data}' | jq -s '.' -``` - -#### **Response example:** - -```json -[ - { - "name": "demo", - "id": "5bb755f42f78660012bdd9af", - "stats": { - "cpu": 3, - "mem": 36.73548113271163, - "cache": 4.689083037753453, - "disk": [ - { - "name": "xvda2", - "value": 84.84461326890819 - } - ] - } - } -] +#!/bin/bash + +# El ID del monitor que se quiere solicitar +monitor_id="60d2586a830e950019051dc0" + +curl -sS "https://supervisor.theeye.io/monitor/${monitor_id}?access_token=${THEEYE_ACCESS_TOKEN}&customer=${THEEYE_ORGANIZATION_NAME}" +``` + +##### **Javascript** + +##### Nota: + +> Se asume que están declaradas las variables `window.THEEYE_ORGANIZATION_NAME` como el nombre de la organización y `window.THEEYE_TOKEN` como la Secret Key de la tarea + +```javascript +// El ID del monitor que se quiere solicitar +const monitor_id = "60d2586a830e950019051dc0" + +let xhr = new XMLHttpRequest(); +xhr.open('GET', `https://supervisor.theeye.io/monitor/${monitor_id}?access_token=${window.THEEYE_ACCESS_TOKEN}&customer=${window.THEEYE_ORGANIZATION_NAME}`); + +xhr.onload = () => { + console.log(JSON.parse(xhr.response)) +} + +xhr.send(null) ``` -#### **Example 4** +##### **Node.js** + +##### Nota: + +> Se asume que están declaradas las variables de entorno `THEEYE_ORGANIZATION_NAME` como el nombre de la organización y `THEEYE_ACCESS_TOKEN` como la Secret Key de la tarea + +```javascript +const https = require('https') + +// El ID del monitor que se quiere solicitar +const monitor_id = "60d2586a830e950019051dc0" + +const options = { + host: 'supervisor.theeye.io', + path: `/monitor/${monitor_id}?access_token=${process.env.THEEYE_ACCESS_TOKEN}&customer=${process.env.THEEYE_ORGANIZATION_NAME}`, + method: 'GET' +} + +const req = https.request(options, res => { + let data = '' + + res.on('data', d => { + data = data + d + }) + + res.on('end', () => { + console.log(JSON.parse(data)) + }) +}) + +req.on('error', error => { + console.error(error) +}) + +req.end() +``` + +##### **Python** + +##### Nota: + +> Se asume que están declaradas las variables de entorno `THEEYE_ORGANIZATION_NAME` como el nombre de la organización y `THEEYE_ACCESS_TOKEN` como la Secret Key de la tarea +> +> También se asume que está instalada la librería [`requests`](https://pypi.python.org/pypi/requests/), de no tenerla puede instalarla usando `pip` + +```python +import os +import requests + +# El ID del Monitor que se quiere solicitar +monitor_id = "60d2586a830e950019051dc0" + +url = "https://supervisor.theeye.io/monitor/" + monitor_id + +params = { + "access_token": os.getenv("THEEYE_ACCESS_TOKEN"), + "customer": os.getenv("THEEYE_ORGANIZATION_NAME") +} + +r = requests.get(url, params) + +print(r.json()) +``` + + + +### **Ejemplo 4** + +#### Eliminar un Monitor + +En este ejemplo enviaremos un DELETE request que eliminará un monitor de una organización. + + + +##### **Bash** + +##### Nota: + +> Se asume que están declaradas las variables de entorno `THEEYE_ORGANIZATION_NAME` como el nombre de la organización y `THEEYE_ACCESS_TOKEN` como la Secret Key de la tarea -##### **Delete Monitor** ```bash +#!/bin/bash -customer=$(echo $THEEYE_ORGANIZATION_NAME | jq -r '.') -token=$THEEYE_ACCESS_TOKEN -id_monitor=$1 +# El ID del monitor que se quiere solicitar +monitor_id="60d2586a830e950019051dc0" + +curl -X DELETE "https://supervisor.theeye.io/monitor/${monitor_id}?access_token=${THEEYE_ACCESS_TOKEN}&customer=${THEEYE_ORGANIZATION_NAME}" +``` + +##### **Javascript** -curl -X DELETE "https://supervisor.theeye.io/monitor/${id_monitor}?access_token=${token}&customer=${customer}" +##### Nota: + +> Se asume que están declaradas las variables `window.THEEYE_ORGANIZATION_NAME` como el nombre de la organización y `window.THEEYE_TOKEN` como la Secret Key de la tarea + +```javascript +// El ID del monitor que se quiere solicitar +const monitor_id = "60d2586a830e950019051dc0" + +let xhr = new XMLHttpRequest(); +xhr.open('DELETE', `https://supervisor.theeye.io/monitor/${monitor_id}?access_token=${window.THEEYE_ACCESS_TOKEN}&customer=${window.THEEYE_ORGANIZATION_NAME}`); + +xhr.onload = () => { + console.log(JSON.parse(xhr.response)) +} + +xhr.send(null) ``` +##### **Node.js** + +##### Nota: + +> Se asume que están declaradas las variables de entorno `THEEYE_ORGANIZATION_NAME` como el nombre de la organización y `THEEYE_ACCESS_TOKEN` como la Secret Key de la tarea + +```javascript +const https = require('https') + +// El ID del monitor que se quiere solicitar +const monitor_id = "60d2586a830e950019051dc0" + +const options = { + host: 'supervisor.theeye.io', + path: `/monitor/${monitor_id}?access_token=${process.env.THEEYE_ACCESS_TOKEN}&customer=${process.env.THEEYE_ORGANIZATION_NAME}`, + method: 'DELETE' +} + +const req = https.request(options, res => { + let data = '' -#### **Example 5** + res.on('data', d => { + data = data + d + }) -##### **Create Web Check Monitor** + res.on('end', () => { + console.log(JSON.parse(data)) + }) +}) + +req.on('error', error => { + console.error(error) +}) + +req.end() +``` + +##### **Python** + +##### Nota: + +> Se asume que están declaradas las variables de entorno `THEEYE_ORGANIZATION_NAME` como el nombre de la organización y `THEEYE_ACCESS_TOKEN` como la Secret Key de la tarea +> +> También se asume que está instalada la librería [`requests`](https://pypi.python.org/pypi/requests/), de no tenerla puede instalarla usando `pip` + +```python +import os +import requests + +# El ID del Monitor que se quiere solicitar +monitor_id = "60d2586a830e950019051dc0" + +url = "https://supervisor.theeye.io/monitor/" + monitor_id + +params = { + "access_token": os.getenv("THEEYE_ACCESS_TOKEN"), + "customer": os.getenv("THEEYE_ORGANIZATION_NAME") +} + +r = requests.delete(url, params) + +print(r.json()) +``` + + + +#### **Ejemplo 5** + +##### **Crear un Monitor para el estado de una página** + +En este ejemplo enviaremos un POST request para crear un Monitor de tipo *Scraper* + + ```bash customer=$(echo $THEEYE_ORGANIZATION_NAME | jq -r '.') @@ -109,30 +473,159 @@ curl -sS -X POST "https://supervisor.theeye.io/monitor?access_token=${token}&cus --header 'Content-Type: application/json' \ --data "{\"name\":\"${monitorName}\",\"host_id\":\"${host_id}\",\"url\":\"${url}\",\"timeout\":\"5000\",\"looptime\":\"15000\",\"type\":\"scraper\",\"status_code\":\"200\",\"_type\":\"ScraperMonitor\"}" ``` -#### **Example 6** -##### **Get Monitor by Id** + +{ + "name": "Check BTC price in USDC 2", + "type": "scraper", + "host_id": "60d2586a830e950019051dbe", + "_type": "ScraperMonitor", + "looptime": 10000, + "status_code": "200", + "method": "GET", + "timeout": "5000", + "url": "https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDC" +} + + + +##### **Bash** + +##### Nota: + +> Se asume que están declaradas las variables de entorno `THEEYE_ORGANIZATION_NAME` como el nombre de la organización y `THEEYE_ACCESS_TOKEN` como la Secret Key de la tarea. El `host_id` es el ID del agente que ejecutará la tarea ```bash -customer=$(echo $THEEYE_ORGANIZATION_NAME | jq -r '.') token=$THEEYE_ACCESS_TOKEN -id_monitor=$1 +#!/bin/bash + +curl -sS -X POST "https://supervisor.theeye.io/monitor?access_token=${THEEYE_ACCESS_TOKEN}&customer=${THEEYE_ORGANIZATION_NAME}&host_id=${host_id}" \ +--header 'Content-Type: application/json' \ +--data '{ + "name": "Check BTC price in USDC 2", + "type": "scraper", + "host_id": "${host_id}", + "_type": "ScraperMonitor", + "looptime": 10000, + "status_code": "200", + "method": "GET", + "timeout": "5000", + "url": "https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDC" +}' +``` + +##### **Javascript** + +##### Nota: +> Se asume que están declaradas las variables `window.THEEYE_ORGANIZATION_NAME` como el nombre de la organización y `window.THEEYE_TOKEN` como la Secret Key de la tarea. El `host_id` es el ID del agente que ejecutará la tarea -curl -sS -X GET "https://supervisor.theeye.io/monitor/${id_monitor}?access_token=${token}&customer=${customer}" +```javascript +const monitor = { + "name": "Check BTC price in USDC 2", + "type": "scraper", + "host_id": host_id, + "_type": "ScraperMonitor", + "looptime": 10000, + "status_code": "200", + "method": "GET", + "timeout": "5000", + "url": "https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDC" +} + +let xhr = new XMLHttpRequest(); +xhr.open('POST', `https://supervisor.theeye.io/monitor?access_token=${window.THEEYE_TOKEN}&customer=${window.THEEYE_ORGANIZATION_NAME}&host_id=${host_id}`); + +xhr.setRequestHeader("Accept", "application/json") +xhr.setRequestHeader("Content-Type", "application/json") + +xhr.onload = () => { + console.log(JSON.parse(xhr.response)) +} + +xhr.send(JSON.stringify(monitor)) ``` -#### **Example 7** -##### **Get Monitor by name** +##### **Node.js** + +##### Nota: + +> Se asume que están declaradas las variables de entorno `THEEYE_ORGANIZATION_NAME` como el nombre de la organización y `THEEYE_ACCESS_TOKEN` como la Secret Key de la tarea. El `host_id` es el ID del agente que ejecutará la tarea + +```javascript +const https = require('https') + +const monitor = { + "name": "Check BTC price in USDC 2", + "type": "scraper", + "host_id": host_id, + "_type": "ScraperMonitor", + "looptime": 10000, + "status_code": "200", + "method": "GET", + "timeout": "5000", + "url": "https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDC" +} + +const options = { + host: 'supervisor.theeye.io', + path: `monitor?access_token=${process.env.THEEYE_TOKEN}&customer=${process.env.THEEYE_ORGANIZATION_NAME}&host_id=${host_id}`, + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + } +} + +const req = https.request(options, res => { + let data = '' -```bash -customer=$(echo $THEEYE_ORGANIZATION_NAME | jq -r '.') -token=$THEEYE_ACCESS_TOKEN -nameMonitor=$1 + res.on('data', d => { + data = data + d + }) + res.on('end', () => { + console.log(JSON.parse(data)) + }) +}) -curl -sS -X GET "https://supervisor.theeye.io/monitor?access_token=${token}&where\[name\]=${nameMonitor}" +req.on('error', error => { + console.error(error) +}) + +req.write(JSON.stringify(body)) +req.end() ``` +##### **Python** + +##### Nota: + +> Se asume que están declaradas las variables de entorno `THEEYE_ORGANIZATION_NAME` como el nombre de la organización y `THEEYE_ACCESS_TOKEN` como la Secret Key de la tarea. El `host_id` es el ID del agente que ejecutará la tarea +> +> También se asume que está instalada la librería [`requests`](https://pypi.python.org/pypi/requests/), de no tenerla puede instalarla usando `pip` +```python +import os +import requests +const monitor = { + "name": "Check BTC price in USDC 2", + "type": "scraper", + "host_id": host_id, + "_type": "ScraperMonitor", + "looptime": 10000, + "status_code": "200", + "method": "GET", + "timeout": "5000", + "url": "https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDC" +} + +url = "https://supervisor.theeye.io/monitor?access_token=" + os.getenv(THEEYE_TOKEN) * "&customer=" + os.getenv(THEEYE_ORGANIZATION_NAME) + "&host_id=" + host_id + + +r = requests.post(url, monitor) + +print(r.json()) +``` + \ No newline at end of file diff --git a/docs/sync/README.md b/docs/sync/README.md index 3456d321..668bb823 100644 --- a/docs/sync/README.md +++ b/docs/sync/README.md @@ -1,6 +1,8 @@ [![theeye.io](../images/logo-theeye-theOeye-logo2.png)](https://theeye.io/en/index.html) -# Sync API +# API Sync + +Ejecución sincrónica de tareas. ## URL @@ -8,32 +10,66 @@ ____ -Tasks execution in TheEye is asynchronous by nature. This means, that task will get executed and then continue in background an the time it takes to complete varies. Usually, we do not need to wait the result and we can check it later. +La ejecución de tareas individuales en TheEye es asincrónica por la naturaleza de los procesos. +Esto se debe a que las tareas en general son ejecutadas en lotes mediante el uso de "Queues". El tiempo y la complejidad varía en cada implementación. +Habitualmente no necesitamos esperar el resultado de forma instantanea. + +En algunos casos es necesario obtener el resultado de la ejecución de forma inmediata. +Este es aún común si necesitamos que las tareas se comporten como si fueran métodos de una API Rest. -But there are cases when we need to invoke the task and we want to wait the result. This is very common when connecting apis, using task with interfaces that requires user interaction and many other escenarios. +Este comportamiento puede ser logrado utilizando la API en modo Sync. +Cualquier tarea puede ser utilizada mediante la API Sync. Es necesario tener en cuenta que con tiempo de ejecución muy largos se pueden producir Timeouts o incluso el orquestador puede cortar la comunicación de forma repentina. -This can be achived using the API in sync mode. The only restriction is the task execution timeout. A recommended timeout would be between 10 to 30 seconds maximum. Most of the web client will abort the request near the 60 seconds. Clients behaviour can be configured and changed but experience tells us that it is not recommended, unless you really need it. +Un tiempo de respuesta razonable no debe superar los 60 segundos de ejecución ___ -## API Paths +## Rutas | Method | Path | Description | ACL | | ---- | ----| ----| ----| | POST | /${customer}/task/${id}/job | [Run task](#waiting-output) | user | +## Argumentos + + +| Name | Values | Description | +| ---- | ---- | ---- | +| result | empty/null. is ignored | Result es la información informada por el Agente al finalizar la ejecución. En otros incluye execution log, output, lastline. | +| full | empty/null. is ignored | Responde con el document Job completo asociado a la ejecución. El mismo documento puede ser obtenido haciendo un GET a la API de jobs | +| parse | empty or a Number/Integer > 0 | El output de un job es almacenado en la base de datos como un Array de Strings, que si fuera encadenado serán argumentos de la siguiente tarea. La opción parse utilizara por defecto el índice 0 de este array de outputs y lo intentara interpretar como JSON. En algunos casos puede ser necesario utilizar un índice diferente al 0, sobre todo si se trabaja con outputs de tareas ya definidios en otras implementaciones. Usando parse=INDEX_NUM donde INDEX_NUM es un número entero del output. Si el índice no esta presente o no es posible interpretarlo se devuelve el output crudo | + + +## Respuesta + + +Por defecto la API Sync responde con el output obtenido de la ejecución de la tarea. El output es lo que desde la interfaz se visualiza en la sección "output" del resultado de la ejecución. + +El output se almacena en la base de datos dentro del documento job. El job representa la instancia de ejecución de la tarea. + + +| State | HTTP Status Code | +| ---- | ---- | +| success | 200 | +| failure | 500 | + + ### NOTES -* Single **Task execution** is supported. Workflows execution is **NOT Possible** at this moment. +* Por el momento solo es posible la ejecución de _Tareas Individuales_ . -___ +____ -## Examples -### Waiting output +## Ejemplos + +Puede descargar e importa [esta receta utilizada para todos los ejemplos](/sync/Rest_API_Response.json ":ignore") + + +### Esperando output ```bash @@ -45,3 +81,131 @@ curl -s -X POST "https://sync.theeye.io/${customer}/task/${taskId}/job?access_to ``` + +### Ejemplo de resultado "failure" + + +```bash + +curl -i -X POST 'https://sync.theeye.io/${customer_id}/task/${task_id}/job?access_token=${token}' \ + --header 'content-type: application/json' \ + --data '{"task_arguments":[200]}' + +``` + + +```http + +HTTP/1.1 500 Internal Server Error +X-Powered-By: Express +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET,PUT,PATCH,POST,DELETE,OPTIONS +Access-Control-Allow-Credentials: true +Access-Control-Allow-Headers: Origin, Accept, User-Agent, Accept-Charset, Cache-Control, Accept-Encoding, Content-Type, Authorization, Content-Length, X-Requested-With +Content-Type: application/json; charset=utf-8 +Content-Length: 135 +ETag: W/"87-+Fzdxc2Q7NsFIfhclF3lcqgSScY" +Date: Fri, 28 Jan 2022 16:59:54 GMT +Connection: keep-alive +Keep-Alive: timeout=5 + +["{\"message\":\"Validation Error. Invalid Argument Value\",\"statusCode\":418,\"name\":\"ClientError\",\"code\":\"\",\"status\":418}"] + + +``` + +### Ejemplo de resultado "success" + + +```bash + +curl -i -X POST 'https://sync.theeye.io/${customer_id}/task/${task_id}/job?access_token=${token}' \ + --header 'content-type: application/json' \ + --data '{"task_arguments":[100]}' + +``` + +```http + +HTTP/1.1 200 OK +X-Powered-By: Express +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET,PUT,PATCH,POST,DELETE,OPTIONS +Access-Control-Allow-Credentials: true +Access-Control-Allow-Headers: Origin, Accept, User-Agent, Accept-Charset, Cache-Control, Accept-Encoding, Content-Type, Authorization, Content-Length, X-Requested-With +Content-Type: application/json; charset=utf-8 +Content-Length: 62 +ETag: W/"3e-Earn8PE7JwarkhTciq4Sn4inI3g" +Date: Fri, 28 Jan 2022 17:00:22 GMT +Connection: keep-alive +Keep-Alive: timeout=5 + +["{\"name\":\"tomer\",\"date\":\"2022-01-28T17:00:22.676Z\"}"] + +``` + + +### Ejemplo de "success" usando "parse" + + +Get the ID and replace in the requests below + +```bash + +curl -i -X POST 'https://sync.theeye.io/${customer_id}/task/${task_id}/job?parse&access_token=${token}' \ + --header 'content-type: application/json' \ + --data '{"task_arguments":[100]}' + +``` + + +```http + +HTTP/1.1 200 OK +X-Powered-By: Express +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET,PUT,PATCH,POST,DELETE,OPTIONS +Access-Control-Allow-Credentials: true +Access-Control-Allow-Headers: Origin, Accept, User-Agent, Accept-Charset, Cache-Control, Accept-Encoding, Content-Type, Authorization, Content-Length, X-Requested-With +Content-Type: application/json; charset=utf-8 +Content-Length: 50 +ETag: W/"32-QGrCXrCY2sEcc1V/fL6omhdvPKY" +Date: Fri, 28 Jan 2022 16:26:41 GMT +Connection: keep-alive +Keep-Alive: timeout=5 + +{"name":"tomer","date":"2022-01-28T16:26:41.201Z"} + +``` + +### Ejemplo de "failure" usando "parse" + + +```bash + +curl -i -X POST 'https://sync.theeye.io/${customer_id}/task/${task_id}/job?parse&access_token=${token}' \ + --header 'content-type: application/json' \ + --data '{"task_arguments":[200]}' + +``` + + +```http + +HTTP/1.1 418 I'm a Teapot +X-Powered-By: Express +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET,PUT,PATCH,POST,DELETE,OPTIONS +Access-Control-Allow-Credentials: true +Access-Control-Allow-Headers: Origin, Accept, User-Agent, Accept-Charset, Cache-Control, Accept-Encoding, Content-Type, Authorization, Content-Length, X-Requested-With +Content-Type: application/json; charset=utf-8 +Content-Length: 115 +ETag: W/"73-FBmPIgGdDNzn6NM27joxlSUMWp4" +Date: Fri, 28 Jan 2022 16:56:47 GMT +Connection: keep-alive +Keep-Alive: timeout=5 + +{"message":"Validation Error. Invalid Argument Value","statusCode":418,"name":"ClientError","code":"","status":418} + +``` + diff --git a/docs/sync/Rest_API_Response.json b/docs/sync/Rest_API_Response.json new file mode 100644 index 00000000..25787983 --- /dev/null +++ b/docs/sync/Rest_API_Response.json @@ -0,0 +1 @@ +{"task":{"order":0,"enable":true,"type":"script","public":false,"tags":[],"grace_time":0,"task_arguments":[{"id":1,"order":0,"type":"input","label":"number","value":"","help":"","readonly":false,"required":true,"multiple":false,"masked":false,"charsmin":0,"charsmax":0,"charset":null,"pattern":"","options":[]}],"arguments_type":"legacy","output_parameters":[],"register_body":false,"execution_count":83,"multitasking":true,"show_result":false,"assigned_users":[],"user_inputs":false,"user_inputs_members":[],"empty_viewers":false,"cancellable":true,"autoremove_completed_jobs_limit":5,"script_arguments":[{"id":1,"order":0,"type":"input","label":"number","value":"","help":"","readonly":false,"required":true,"multiple":false,"masked":false,"charsmin":0,"charsmax":0,"charset":null,"pattern":"","options":[]}],"logging":false,"_type":"ScriptTask","creation_date":"2022-01-28T13:01:43.355Z","last_update":"2022-01-28T16:56:46.292Z","env":{"NODE_ENV":""},"name":"Rest API Response","description":"","timeout":600000,"allows_dynamic_settings":false,"script_runas":"node %script%","template":null,"template_id":null,"source_model_id":"61f3e937c38201da80f96c27"},"file":{"order":0,"filename":"api.js","keyname":"api.js[ts:1643388995376]","mimetype":"text/javascript","extension":"js","size":2079,"description":"","md5":"824a8455060c66ebce1408efb52652dd","public":false,"tags":[],"source_model_id":"61f3e92cc38201da80f96c26","data":"Ly8gZXJyb3IgYW5kIG91dHB1dCBoYW5kbGVycyBtdXN0IGdvIGZpcnN0LgoKLyoqCiAqIEBwYXJhbSB7T2JqZWN0fQogKiBAcHJvcCB7TWl4ZWR9IGRhdGEKICogQHByb3Age0FycmF5fSBjb21wb25lbnRzCiAqIEBwcm9wIHtPYmplY3R9IG5leHQKICovCmNvbnN0IHN1Y2Nlc3NPdXRwdXQgPSAoeyBkYXRhLCBjb21wb25lbnRzLCBuZXh0IH0pID0+IHsKICAvLyBodHRwczovL2RvY3VtZW50YXRpb24udGhlZXllLmlvL2NvcmUtY29uY2VwdHMvc2NyaXB0cy8jcGFzc2luZy1hcmd1bWVudHMtaW4td29ya2Zsb3cKICBjb25zdCBvdXRwdXQgPSB7CiAgICBzdGF0ZTogInN1Y2Nlc3MiLAogICAgZGF0YSwKICAgIGNvbXBvbmVudHMsIC8vIGh0dHBzOi8vZG9jdW1lbnRhdGlvbi50aGVleWUuaW8vY29yZS1jb25jZXB0cy90YXNrcy9zY3JpcHRfdHlwZS8jY29tcG9uZW50cwogICAgbmV4dAogIH0KICBjb25zb2xlLmxvZyggSlNPTi5zdHJpbmdpZnkob3V0cHV0KSApCiAgcHJvY2Vzcy5leGl0KDApCn0KCi8qKgogKiBAcGFyYW0ge0Vycm9yfSBlcnIKICovCmNvbnN0IGZhaWx1cmVPdXRwdXQgPSAoZXJyKSA9PiB7CiAgY29uc29sZS5lcnJvcihlcnIpCiAgY29uc3Qgb3V0cHV0ID0gewogICAgc3RhdGU6ICJmYWlsdXJlIiwKICAgIGRhdGE6IGVycgogIH0KICBjb25zb2xlLmVycm9yKCBKU09OLnN0cmluZ2lmeShvdXRwdXQpICkKICBwcm9jZXNzLmV4aXQoMSkKfQoKcHJvY2Vzcy5vbigndW5oYW5kbGVkUmVqZWN0aW9uJywgKHJlYXNvbiwgcCkgPT4gewogIGNvbnNvbGUuZXJyb3IocmVhc29uLCAnVW5oYW5kbGVkIFJlamVjdGlvbiBhdCBQcm9taXNlJywgcCkKICBmYWlsdXJlT3V0cHV0KHJlYXNvbikKfSkKCnByb2Nlc3Mub24oJ3VuY2F1Z2h0RXhjZXB0aW9uJywgZXJyID0+IHsKICBjb25zb2xlLmVycm9yKGVyciwgJ1VuY2F1Z2h0IEV4Y2VwdGlvbiB0aHJvd24nKQogIGZhaWx1cmVPdXRwdXQoZXJyKQp9KQoKLy8gTm9kZUpzIGJvaWxlcnBsYXRlCmNvbnN0IG1haW4gPSBhc3luYyAoKSA9PiB7CiAgY29uc3QgYXJncyA9IHByb2Nlc3MuYXJndi5zbGljZSgyKQoKICBpZiAoYXJnc1swXSA+IDEwMCkgewogICAgdGhyb3cgbmV3IENsaWVudEVycm9yKCdWYWxpZGF0aW9uIEVycm9yLiBJbnZhbGlkIEFyZ3VtZW50IFZhbHVlJywgeyBzdGF0dXNDb2RlOiA0MTggfSkKICB9CgogIGNvbnN0IHJlc3VsdCA9IHsKICAgIGRhdGE6IHsKICAgICAgbmFtZTogInRvbWVyIiwKICAgICAgZGF0ZTogbmV3IERhdGUoKQogICAgfSwKICAgIGNvbXBvbmVudHM6IHsgInBvcHVwIjogIkhpIFdvcmxkISIgfSwKICAgIG5leHQ6IHt9CiAgfQoKICAvLyBhZGQgeW91ciBjb2RlIGhlcmUuCgogIHJldHVybiByZXN1bHQKfQoKY2xhc3MgQ2xpZW50RXJyb3IgZXh0ZW5kcyBFcnJvciB7CiAgY29uc3RydWN0b3IgKG1lc3NhZ2UsIG9wdGlvbnMpIHsKICAgIHN1cGVyKG1lc3NhZ2UgfHwgJ0ludmFsaWQgUmVxdWVzdCcpCiAgICBvcHRpb25zfHwob3B0aW9ucz17fSkKICAgIE9iamVjdC5hc3NpZ24odGhpcywgb3B0aW9ucykKICAgIHRoaXMubmFtZSA9IHRoaXMuY29uc3RydWN0b3IubmFtZQogICAgdGhpcy5jb2RlID0gb3B0aW9ucy5jb2RlIHx8ICcnCiAgICB0aGlzLnN0YXR1cyA9IG9wdGlvbnMuc3RhdHVzQ29kZSB8fCA0MDAKICB9CiAgCiAgdG9KU09OICgpIHsKICAgIGxldCBhbHQgPSB7fQogICAgbGV0IHN0b3JlS2V5ID0gZnVuY3Rpb24gKGtleSkgewogICAgICBpZiAoa2V5ID09PSAnc3RhY2snKSB7CiAgICAgICAgaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSAncHJvZHVjdGlvbicpIHsKICAgICAgICAgIGFsdFtrZXldID0gdGhpc1trZXldCiAgICAgICAgfQogICAgICB9IGVsc2UgewogICAgICAgIGFsdFtrZXldID0gdGhpc1trZXldCiAgICAgIH0KICAgIH0KICAgIE9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKHRoaXMpLmZvckVhY2goc3RvcmVLZXksIHRoaXMpCiAgICByZXR1cm4gYWx0CiAgfQp9CgoKCi8vIGludm9rZSBtYWluIGFuZCBjYXB0dXJlIHJlc3VsdCBvdXRwdXQKbWFpbigpLnRoZW4oc3VjY2Vzc091dHB1dCkuY2F0Y2goZmFpbHVyZU91dHB1dCkK"}} \ No newline at end of file diff --git a/docs/tasks/README.md b/docs/tasks/README.md index e90068b8..2c2d0e00 100644 --- a/docs/tasks/README.md +++ b/docs/tasks/README.md @@ -1,250 +1,593 @@ -[![theeye.io](../images/logo-theeye-theOeye-logo2.png)](https://theeye.io/en/index.html) +[![theeye.io](../../images/logo-theeye-theOeye-logo2.png)](https://theeye.io/index.html) # Tasks API -____ +## Direcciones de API -## API Paths +| Method | Path | Description | ACL | +| ------ | ----------------------------------------------------- | ------------------------------------------ | --------- | +| GET | /${customer}/task | [Enlistar tareas](#ejemplo-1) | viewer | +| GET | /${customer}/task/${id} | [Buscar por ID](#ejemplo-2) | viewer | +| DELETE | /${customer}/task/${id} | Eliminar tarea | admin | +| GET | /${customer}/task/:task/recipe | Buscar receta | admin | +| GET | /${customer}/task/import | Crear desde receta | admin | +| GET | /${customer}/task/:task/credentials | Buscar credenciales de tarea | admin | +| POST | /${customer}/task/${id}/job | Ejecutar tarea | user | +| POST | /${customer}/task/${id}/secret/${task_secret_key}/job | [Ejecutar tarea con su key](#ejemplo-3) | anonymous | +| DELETE | /${customer}/task/${id}/job | Vaciar cola de jobs | admin | -| Method | Path | Description | ACL | -| ----- | ----- | ----- | ----- | -| GET | /${customer}/task | [List all](#example-1) | viewer | -| | | [List and timeout](#example-3) | viewer | -| GET | /${customer}/task/${id} | [Get by id](#example-2) | viewer | -| DELETE | /${customer}/task/${id} | Remove task | admin | -| GET | /${customer}/task/:task/recipe | Get task recipe | admin | -| GET | /${customer}/task/import | Create from recipe | admin | -| GET | /${customer}/task/:task/credentials | Get task secret | admin | -| POST | /${customer}/task/${id}/job | Run task | user | -| POST | /${customer}/task/${id}/secret/${task_secret_key}/job | [Using task secret key](#example-4) | anonymous | -| DELETE | /${customer}/task/${id}/job | Empty jobs queue | admin | +### NOTAS -### NOTES +* *customer* (OBLIGATORIO) + + > Puede incluirse en el cuerpo del request como `"customer"` -* _customer_ (REQUIRED) +* *access_token* (OBLIGATORIO) + + > Puede inclurse en el Authorization header \(`Authorization: Bearer ${token}`\) - Can be included in the body as "customer" - -* _access_token_ (REQUIRED) +----- - Can be provided vía Authorization header \( Authorization: Bearer ${token} \) +## Propiedades del Modelo + +| Nombre de Propiedad | Nombre en la UI | Tipo | Descripción | +| ------------------- | -------------------- | ------------- |:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| name | Name | string | Nombre de la tarea | +| host_id | Bots | string | El host en el que se ejecuta | +| script_id | Script | string | El script que ejecuta | +| tags | Tags | strings array | Lista de etiquetas para identificar fácilmente | +| task_arguments | Task Arguments | array | Los parámetros de la tarea a ejecutar. [Más información](https://documentation.theeye.io/theeye-web/#/es/core-concepts/tasks/?id=task-arguments) | +| run_as | Run As | string | El comando que ejecuta la tarea. [Más información](../scripts/runas.md) | +| description | Description | string | Una descripción de la tarea, puede (pero no se limita a) describir su funcionamiento y/o su output | +| acls | ACL's | array | Los usuarios que pueden ver la tarea \(los permisos dependen del tipo de usuario que sean\) | +| triggers | Triggered by | array | Eventos que dispararán la tarea automáticamente (opcional). [Más información](/core-concepts/tasks/triggers.md) | +| grace_time | Trigger on-hold time | number | Tiempo desde uno de los eventos definidos anteriormente hasta el disparo de la tarea | +| timeout | Execution Timeout | number | Cuánto esperar la respuesta del servidor antes de cancelar ejecución. Si se excede el timeout, el Bot va a intentar detener la ejecución enviando señales de `SIGTERM` y `SIGKILL` (default **600**) | +| multitasking | Multitasking | boolean | Permite a los Bots ejecutar multiples Jobs de esta tarea en paralelo | +| env | Environment (env) | string | Declara variables de entorno extra para definir previo a la ejecución del script | + +### NOTAS + +* _timeout_ + + > El timeout de ejecución por defecto son 10 minutos.
+ > Aún no es posible cambiar el timeout mediante la API.
+ > Para modificar el timeout de una tarea, utilice la interfaz Web. ----- +## Ejecutar tareas (Tasks) + +Para ejecutar una **tarea**, se crea internamente un **Job** y se agrega a la cola de ejecución. Si se desea ejecutar una **tarea** solo necesita crear un **Job** manualmente y pasarle el ID de la tarea \(y sus opciones\) que quiere correr. + +Nótese que en este ejemplo estamos ejecutando una tarea sin argumentos, y por ende `task_arguments` es un array vacío. Para ejecutar una tarea con argumentos, debe proveer la lista de argumentos correctamente ordenada en el parámetro `task_arguments`. Cada argumento debe ser una string de JSON escapada válida. + +Esto puede hacerse fácilmente con un POST request al endpoint de Job de la API. + +Hay 2 métodos disponibles: + +### Payload de ejecución de tarea/Workflow via API + +Al crear Jobs de tareas mediante la API, tendrá que proveer el ID de la tarea y sus argumentos. + +```javascript +{ + // (Obligatorio) + task: "task id", + // (Solo necesario si la tarea tiene argumentos) + task_arguments: [] +} +``` + +### Usando la Secret Key de la tarea (recomendado) -## Model Properties +Todas las tareas y los Workflows tienen una **Secret Key**, una contraseña que se puede usar para invocarlos diréctamente desde la API. Estas contraseñas se asignan por tarea/Workflow y son **unicas para estos**, es decir, solo hay una Secret Key por tarea y Workflow. -| Property Name | UI Name | Type | Default | Description | -| ----- | ----- | ----- | | ----- | -| name | Name | string | | name your task | -| host_id | Bots | string | | select the host where the script will run | -| script_id | Script | string | | select the script to be executed by the task | -| tags | Tags | strings array | | tag your task so you can find quickly through the application. | -| task_arguments | Task Arguments | array | | If the script played by the task is meant to receive parameters you can set them from here. Mind the order as it will be used by the script. _Fixed_, _options_, and _input_ arguments are allowed. _Input_ and _options_ arguments will be asked to the user for execution. _Fixed_ arguments will not be displayed to the user at execution time. | -| run_as | Run As | string | | write down any extra command or argument needed to run the script. Windows users must declare here which interpreter to use. Linux users could prepend sudo | -| description | Description | text | | describe your task. What does it do, what's the expected output after execution | -| acls | ACL's | array | | select who can view your task \(what can be done with the task depends on the user role\) | -| triggers | Triggered by | array | | If the task is part of a workflow, select what triggers the task. The task will be triggered by the resource you selected here. | -| grace_time | Trigger on-hold time | number | | enter the time period TheEye should wait before running the task. _No wait / Cancelation_ can be selected which means the task will run inmediately after triggered. \(only applicable for triggered tasks\). **To cancel the task execution during the grace period, go to tasks panel, expand the task and delete the schedule created by the trigger.** | -| timeout | Execution Timeout | number | 600 | This is the number of seconds the Bot will wait for the script to complete the execution. If the timeout is exceeded the Bot will try to terminate(kill) the script, sending SIGTERM/SIGKILL signal | -| multitasking | Multitasking | boolean | | enable or disable parallel execution of the task. When this is enable assigned bot will be able to run multiple instances of the Job at same time. this is important to check when running DesktopBots | -| env | Environment (env) | string | | Define extra environment variables that will be present during script execution | +Las Secret Keys pueden revocarse en cualquier momento tan solo cambiándolas, lo que hace este método el recomendado para acceder a la API gracias a su simpleza y seguridad. -### NOTES +### Usando claves de integración general -* _timeout_ +Un usuario administrador puede crear una clave de integración (API Integration Token) desde la interfaz, la cual luego funciona para realizar múltiples operaciones desde la API. Para crearla, haga click en el ícono de su perfil, luego diríjase a *Settings* ➔ *Credentials* ➔ *Integration Tokens* - The default execution timeout for tasks is 10 minutes. - - Now it's not possible to change the timeout via API. +> :warning: Las claves de integración tienen completos **permisos de ADMINISTRADOR**, almacénela en un lugar seguro - To modify the timeout for a task use the Web Interface. +Revise el [ejemplo 4](#ejemplo-4) para más información ----- -## Running tasks +## Ejemplos -For a **Task** to run, internally, a new **Job** is created and added to the queue. If you want to run a **task** you only need to create a **Job** manually and supply the task ID \(and task options\) you want to run. +### **Ejemplo 1** -Note that in this example we are executing a task with no arguments, task_arguments is an empty array. -To execute a task with arguments, provide the list of ordered arguments in the "task_arguments" parameter. -Each argument must be a valid JSON escaped string. +#### Enlistar tareas -This is easily done with a POST request to the Job endpoint API. +En este ejemplo enviaremos un GET request que nos devolverá una lista de todas las tareas disponibles en una organización, con toda la información asociada a cada una de las mismas -There are two methods available. + -### Task and Workflow execution payload via API +##### **Bash** -When creating Task Jobs via API you will have to provide the Task ID and the Task Arguments. +##### Nota: + +> Se asume que están declaradas las variables de entorno `THEEYE_ORGANIZATION_NAME` como el nombre de la organización y `THEEYE_TOKEN` como la Secret Key de la tarea + +```bash +#!/bin/bash + +curl -sS "https://supervisor.theeye.io/$THEEYE_ORGANIZATION_NAME/task?access_token=$THEEYE_TOKEN" +``` + +##### **Javascript** + +##### Nota: + +> Se asume que están declaradas las variables `window.THEEYE_ORGANIZATION_NAME` como el nombre de la organización y `window.THEEYE_TOKEN` como la Secret Key de la tarea ```javascript -{ - // (required) - task: "task id", - // (required only if task has arguments) - task_arguments: [] +let xhr = new XMLHttpRequest(); +xhr.open('GET', `https://supervisor.theeye.io/${window.THEEYE_ORGANIZATION_NAME}/task?access_token=${window.THEEYE_TOKEN}`); + +xhr.onload = () => { + console.log(JSON.parse(xhr.response)) } + +xhr.send(null) ``` -### Using task secret key. Integration Feature \(recommended\) +##### **Node.js** -All tasks and workflows have a **secret key** which can be used to invoke them directly via API. -The secret key provides access to the task it belongs **and only to that task**. -**Secret keys** can be revoked any time by just changing them, which makes this the preferred method for it's implicity and security. +##### Nota: ------ +> Se asume que están declaradas las variables de entorno `THEEYE_ORGANIZATION_NAME` como el nombre de la organización y `THEEYE_TOKEN` como la Secret Key de la tarea -## Examples +```javascript +const https = require('https') + +const options = { + host: 'supervisor.theeye.io', + path: `/${process.env.THEEYE_ORGANIZATION_NAME}/task?access_token=${process.env.THEEYE_TOKEN}`, + method: 'GET' +} +const req = https.request(options, res => { + let data = '' -### **Example 1** -### Get all + res.on('data', d => { + data = data + d + }) -*Resquest* + res.on('end', () => { + console.log(JSON.parse(data)) + }) +}) -```bash -customer=$THEEYE_ORGANIZATION_NAME +req.on('error', error => { + console.error(error) +}) -curl -sS "https://supervisor.theeye.io/${customer}/task?access_token=$THEEYE_TOKEN" +req.end() ``` -### **Example 2** -### Get by id +##### **Python** -*Request* +##### Nota: -```bash -customer=$THEEYE_ORGANIZATION_NAME -task_id=$(echo $THEEYE_JOB | jq -r '.task_id') -echo "task id: ${task_id}" - -result=$(curl -sS "https://supervisor.theeye.io/${customer}/task/${task_id}?access_token=${THEEYE_TOKEN}") - -echo $result | jq -c '. | {"name": .name, "id": .id, "hostname": .hostname}' -``` - -*Response* - -Returns a json array with tasks, id and hostname: -```json -[ - { - "name": "Get IP Address", - "id": "5b1c65ee3c32bb1100c2920a", - "hostname": "Apache3" - }, - { - "name": "Get IP Address", - "id": "5b1c65ee3c32bb1100c29210", - "hostname": "Apache1" - }, - { - "name": "Get IP Address", - "id": "5b1c65efd421031000213bb8", - "hostname": "Apache4" - }, - { - "name": "Get IP Address", - "id": "5b1c65efd421031000213bc6", - "hostname": "Apache2" - } -] +> Se asume que están declaradas las variables de entorno `THEEYE_ORGANIZATION_NAME` como el nombre de la organización y `THEEYE_TOKEN` como la Secret Key de la tarea +> +> También se asume que está instalada la librería [`requests`](https://pypi.python.org/pypi/requests/), de no tenerla puede instalarla usando `pip` + +```python +import os +import requests + +url = "https://supervisor.theeye.io/" + os.getenv("THEEYE_ORGANIZATION_NAME") + "/task" + +params = {"access_token": os.getenv("THEEYE_TOKEN")} + +r = requests.get(url, params) + +print(r.json()) ``` -### **Example 3** -### List and timeout + + +### **Ejemplo 2** + +#### Buscar por ID -(Timeout = null) means that the timeout is set to default (10 minutes). +En este ejemplo enviaremos un GET request que nos devolverá una tarea con toda la información asociada a la misma + + + +##### **Bash** + +##### Nota: + +> Se asume que están declaradas las variables de entorno `THEEYE_ORGANIZATION_NAME` como el nombre de la organización y `THEEYE_TOKEN` como la Secret Key de la tarea ```bash #!/bin/bash -customer=$1 -access_token=$THEEYE_TOKEN -supervisor=$2 -if [ $2 == "" ]; then supervisor='https://supervisor.theeye.io' ; fi -if [ $# -ne 2 ]; then echo "missing parameters" ; exit ; fi +# El ID de la tarea que se quiere solicitar +task_id="61098ee1a3013300120c687b" + +curl -sS "https://supervisor.theeye.io/$THEEYE_ORGANIZATION_NAME/task/${task_id}?access_token=$THEEYE_TOKEN" +``` + +##### **Javascript** + +##### Nota: + +> Se asume que están declaradas las variables `window.THEEYE_ORGANIZATION_NAME` como el nombre de la organización y `window.THEEYE_TOKEN` como la Secret Key de la tarea + +```javascript +let xhr = new XMLHttpRequest(); + +// El ID de la tarea que se quiere solicitar +const task_id = "61098ee1a3013300120c687b" + +xhr.open('GET', `https://supervisor.theeye.io/${window.THEEYE_ORGANIZATION_NAME}/task/${task_id}?access_token=${window.THEEYE_TOKEN}`); + +xhr.onload = () => { + console.log(JSON.parse(xhr.response)) +} + +xhr.send(null) +``` + +##### **Node.js** + +##### Nota: + +> Se asume que están declaradas las variables de entorno `THEEYE_ORGANIZATION_NAME` como el nombre de la organización y `THEEYE_TOKEN` como la Secret Key de la tarea + +```javascript +const https = require('https') + +// El ID de la tarea que se quiere solicitar +const task_id = "61098ee1a3013300120c687b" + + +const options = { + host: 'supervisor.theeye.io', + path: `/${process.env.THEEYE_ORGANIZATION_NAME}/task/${task_id}?access_token=${process.env.THEEYE_TOKEN}`, + method: 'GET' +} + +const req = https.request(options, res => { + let data = '' + + res.on('data', d => { + data = data + d + }) + + res.on('end', () => { + console.log(JSON.parse(data)) + }) +}) + +req.on('error', error => { + console.error(error) +}) + +req.end() +``` + +##### **Python** + +##### Nota: -data=$(curl -s ${supervisor}/${customer}/task?access_token=${access_token}) +> Se asume que están declaradas las variables de entorno `THEEYE_ORGANIZATION_NAME` como el nombre de la organización y `THEEYE_TOKEN` como la Secret Key de la tarea +> +> También se asume que está instalada la librería [`requests`](https://pypi.python.org/pypi/requests/), de no tenerla puede instalarla usando `pip` -echo "${data}" | jq -j '.[] | "id: ", .id, "\ttask: ", .name, "\ttimeout: ", .timeout, "\n"' +```python +import os +import requests + +# El ID de la tarea que se quiere solicitar +task_id = "61098ee1a3013300120c687b" + +url = "https://supervisor.theeye.io/" + os.getenv("THEEYE_ORGANIZATION_NAME") + "/task/" + task_id + +params = {"access_token": os.getenv("THEEYE_TOKEN")} + +r = requests.get(url, params) + +print(r.json()) ``` + + +### **Ejemplo 3** + +### Ejecutar con la Secret Key + +En este ejemplo enviaremos un POST request que ejecutará una tarea de nuestra elección, creando un Job para el agente. Debe proveerse el ID de la tarea y su Secret Key, ilustrado como argumentos de función. Devuelve información del Job que se creó. + + -### **Example 4** -### Execute using secret key +##### **Bash** + +##### Nota: + +> Se asume que está declaradas las variable de entorno `THEEYE_ORGANIZATION_NAME` como el nombre de la organización +> +> Como BASH no permite devolver valores arbitrarios, se imprime el resultado en stdout. Si en su lugar desea guardarlo en una variable, puede ejecutar la función de la siguiente manera:
+> `$ output=$(execTask "ID" "Secret")` ```bash -task_id=$TASK_ID -task_secret_key=$TASK_SECRET -customer=$(echo $THEEYE_ORGANIZATION_NAME | jq -r '.') +execTask () { + task_id=$1 + task_secret_key=$2 + + body='{ "customer": "'"$THEEYE_ORGANIZATION_NAME"'", "task": "'"$task_id"'" }' + + curl -sS \ + --request POST \ + --header "Accept: application/json" \ + --header "Content-Type: application/json" \ + --data ${body} \ + --url "https://supervisor.theeye.io/job/secret/${task_secret_key}" +} +``` + +##### **Javascript** + +##### Nota: + +> Se asume que está declarada las variable `window.THEEYE_ORGANIZATION_NAME` como el nombre de la organización +> +> En este ejemplo, la función devuelve una `Promise` que se resuelve al completar el request + +```javascript +const execTask = (task_id, task_secret_key) => { + return new Promise((resolve, reject) => { + let xhr = new XMLHttpRequest(); -curl -i -sS \ - --request POST \ - --header "Accept: application/json" \ - --header "Content-Type: application/json" \ - --data-urlencode "customer = ${customer}" \ - --data-urlencode "task = ${task_id}" \ - --url "https://supervisor.theeye.io/job/secret/${task_secret_key}" + const body = { + customer: window.THEEYE_ORGANIZATION_NAME, + task: task_id + } + + xhr.open('POST', `https://supervisor.theeye.io/job/secret/${task_secret_key}`); + + xhr.setRequestHeader("Accept", "application/json") + xhr.setRequestHeader("Content-Type", "application/json") + + xhr.onload = () => { + resolve(JSON.parse(xhr.response)) + } + + xhr.onerror = () => { + reject(xhr.response) + } + + xhr.send(JSON.stringify(body)) + }) +} ``` -### **Example 5** -### HTML Button +##### **Node.js** -This technique could be combined with an HTML form to generate an action button. -This is very handy when it is needed to perform actions from email bodies or static web pages. +##### Nota: -```html - -Sample approval request - - - +```python +import os +import requests +def execTask(task_id, task_secret_key): + url = "https://supervisor.theeye.io/job/secret/" + task_secret_key + + body = { + "customer": os.getenv("THEEYE_ORGANIZATION_NAME"), + "task": task_id + } + + r = requests.post(url, body) + return(r.json()) ``` -### **Example 6** -### API integration tokens + + +### **Ejemplo 4** + +### Ejecutar con la clave de integración + +En este ejemplo enviaremos un POST request que ejecutará una tarea de nuestra elección utilizando la clave de integración general. Debe proveerse el ID de la tarea y la clave de integración de la cuenta, ilustrado como argumentos de función. Devuelve información del Job que se creó. + +TODO: PROBARLOS -Integration Tokens can be obtained only by admin users. + -

Integration Tokens has full admin privileges. Keep it safe

+##### **Bash** -Accessing to the web interfaz *Menu > Settings > Credentials > Integration Tokens*. +##### Nota: +> Se asume que está declaradas las variable de entorno `THEEYE_ORGANIZATION_NAME` como el nombre de la organización +> +> Como BASH no permite devolver valores arbitrarios, se imprime el resultado en stdout. Si en su lugar desea guardarlo en una variable, puede ejecutar la función de la siguiente manera:
+> `$ output=$(execTask "ID" "Secret")` ```bash -task_id=$TASK_ID -access_token=$ACCESS_TOKEN -customer=$(echo $THEEYE_ORGANIZATION_NAME | jq -r '.') +execTask () { + task_id=$1 + access_token=$2 + + body='{ "customer": "'"$THEEYE_ORGANIZATION_NAME"'", "task": "'"$task_id"'", "access_token": "'"$access_token"'" }' + + curl -sS \ + --request POST \ + --header "Accept: application/json" \ + --header "Content-Type: application/json" \ + --data ${body} \ + --url "https://supervisor.theeye.io/job" +} +``` + +##### **Javascript** + +##### Nota: + +> Se asume que está declarada las variable `window.THEEYE_ORGANIZATION_NAME` como el nombre de la organización +> +> En este ejemplo, la función devuelve una `Promise` que se resuelve al completar el request + +```javascript +const execTask = (task_id, access_token) => { + return new Promise((resolve, reject) => { + let xhr = new XMLHttpRequest(); + + const body = { + customer: window.THEEYE_ORGANIZATION_NAME, + task: task_id, + access_token: access_token + } + xhr.open('POST', 'https://supervisor.theeye.io/job'); -curl -X POST \ - -H "Accept: application/json" \ - -H "Content-Type: application/json" \ - -d "{\"task_arguments\":[]}" \ - "https://supervisor.theeye.io/job?access_token=${access_token}&customer=${customer}&task=${task_id}" + xhr.setRequestHeader("Accept", "application/json") + xhr.setRequestHeader("Content-Type", "application/json") + xhr.onload = () => { + resolve(JSON.parse(xhr.response)) + } + + xhr.onerror = () => { + reject(xhr.response) + } + + xhr.send(JSON.stringify(body)) + }) +} +``` + +##### **Node.js** + +##### Nota: + +> Se asume que está declaradas las variable de entorno `THEEYE_ORGANIZATION_NAME` como el nombre de la organización +> +> En este ejemplo, la función devuelve una `Promise` que se resuelve al completar el request + +```javascript +const https = require('https') + +const execTask = (task_id, access_token) => { + return new Promise((resolve, reject) => { + const body = { + customer: process.env.THEEYE_ORGANIZATION_NAME, + task: task_id, + access_token: access_token + } + + const options = { + host: 'supervisor.theeye.io', + path: '/job', + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + } + } + + const req = https.request(options, res => { + let data = '' + + res.on('data', d => { + data = data + d + }) + + res.on('end', () => { + console.log(JSON.parse(data)) + }) + }) + + req.on('error', error => { + console.error(error) + }) + + req.write(JSON.stringify(body)) + req.end() + }) +} +``` + +##### **Python** + +##### Nota: +> Se asume que está declaradas las variable de entorno `THEEYE_ORGANIZATION_NAME` como el nombre de la organización +> +> También se asume que está instalada la librería [`requests`](https://pypi.python.org/pypi/requests/), de no tenerla puede instalarla usando `pip` + +```python +import os +import requests + +def execTask(task_id, access_token): + url = "https://supervisor.theeye.io/job" + + body = { + "customer": os.getenv("THEEYE_ORGANIZATION_NAME"), + "task": task_id, + "access_token": access_token + } + + r = requests.post(url, body) + return(r.json()) ``` -The API response is a the created job. We can save the job id and use it later to query the job status. + diff --git a/docs/tasks/arguments.md b/docs/tasks/arguments.md index 80dbffbb..d6c17b87 100644 --- a/docs/tasks/arguments.md +++ b/docs/tasks/arguments.md @@ -1,19 +1,16 @@ -[![theeye.io](../images/logo-theeye-theOeye-logo2.png)](https://theeye.io/en/index.html) +[![theeye.io](../../images/logo-theeye-theOeye-logo2.png)](https://theeye.io/index.html) -# Tasks Arguments +# Argumento de tareas -_____ +## Ejecución de tareas y Workflows mediante API -## Task and Workflows. API execution +Hay varios métodos para ejecutar tareas y workflows diréctamente desde la API. -There are alternatives to directly execute tasks and workflows vía API. +Revise estas secciones de la documentación -Check the following Documentation Sections +[Usando la Secret Key de la tarea (recomendado)](/tasks/#Usando-la-Secret-Key-de-la-tarea-recomendado) - -[Run Task and Workflow using Integration Secret (recomended)](/api/tasks/#using-task-secret-key-integration-feature-40recommended41) - -[Run Task and Workflow using Integration Token (beta)](/api/tasks/#api-integration-tokens) +[Run Task and Workflow using Integration Token (beta)](/tasks/#Usando-claves-de-integración-general) ___ diff --git a/local.sh b/local.sh index a91a9c85..fbf7d0a8 100755 --- a/local.sh +++ b/local.sh @@ -1,6 +1,6 @@ if [ -z "${DEBUG}" ]; then - export DEBUG="*eye*" + export DEBUG="*eye*err*" fi if [ -z "${NODE_ENV}" ]; then diff --git a/misc/playground/password-hash/package-lock.json b/misc/playground/password-hash/package-lock.json new file mode 100644 index 00000000..1a0fd49a --- /dev/null +++ b/misc/playground/password-hash/package-lock.json @@ -0,0 +1,448 @@ +{ + "name": "password-hash", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@mapbox/node-pre-gyp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.5.tgz", + "integrity": "sha512-4srsKPXWlIxp5Vbqz5uLfBN+du2fJChBoYn/f2h991WLdk7jUvcSk/McVLSv/X+xQIPI8eGD5GjrnygdyHnhPA==", + "requires": { + "detect-libc": "^1.0.3", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.1", + "nopt": "^5.0.0", + "npmlog": "^4.1.2", + "rimraf": "^3.0.2", + "semver": "^7.3.4", + "tar": "^6.1.0" + } + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "requires": { + "debug": "4" + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "are-we-there-yet": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", + "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "bcrypt": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.0.1.tgz", + "integrity": "sha512-9BTgmrhZM2t1bNuDtrtIMVSmmxZBrJ71n8Wg+YgdjHuIWYF7SjjmCPZFB+/5i/o/PIeRpwVJR3P+NrpIItUjqw==", + "requires": { + "@mapbox/node-pre-gyp": "^1.0.0", + "node-addon-api": "^3.1.0" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "requires": { + "ms": "2.1.2" + } + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "requires": { + "minipass": "^3.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minipass": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.5.tgz", + "integrity": "sha512-+8NzxD82XQoNKNrl1d/FSi+X8wAEWR+sbYAfIvub4Nz0d22plFG72CEVVaufV8PNf4qSslFTD8VMOxNVhHCjTw==", + "requires": { + "yallist": "^4.0.0" + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==" + }, + "node-fetch": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.3.tgz", + "integrity": "sha512-BXSmNTLLDHT0UjQDg5E23x+0n/hPDjySqc0ELE4NpCa2wE5qmmaEWFRP/+v8pfuocchR9l5vFLbSB7CPE2ahvQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "requires": { + "abbrev": "1" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "signal-exit": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.4.tgz", + "integrity": "sha512-rqYhcAnZ6d/vTPGghdrw7iumdcbXpsk1b8IG/rz+VWV51DM0p7XCtMoJ3qhPLIbp3tvyt3pKRbaaEMZYpHto8Q==" + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "tar": { + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } +} diff --git a/misc/playground/password-hash/package.json b/misc/playground/password-hash/package.json index fba93190..c6ec8a6b 100644 --- a/misc/playground/password-hash/package.json +++ b/misc/playground/password-hash/package.json @@ -10,6 +10,6 @@ "author": "facugon", "license": "ISC", "dependencies": { - "bcrypt": "^0.8.3" + "bcrypt": "~5.0.1" } } diff --git a/package-lock.json b/package-lock.json index 1341878d..933568d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { - "name": "TheEye-Supervisor", - "version": "2.8.3", + "name": "theeye-supervisor", + "version": "3.0.2", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -180,9 +180,9 @@ "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==" }, "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" }, "ansi-styles": { "version": "4.3.0", @@ -207,12 +207,14 @@ "integrity": "sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=" }, "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "requires": { - "sprintf-js": "~1.0.2" - } + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" }, "asn1": { "version": "0.2.4", @@ -241,14 +243,14 @@ } }, "aws-sdk": { - "version": "2.644.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.644.0.tgz", - "integrity": "sha512-FkglRU5fvWHwT2Ll0caXS/QzRNzh5ZCS5cs4pF2nP0OjdD7VNJhNtu5lOnSzvMHAtZQJMsG3k0em8PoI8vk1AQ==", + "version": "2.1088.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1088.0.tgz", + "integrity": "sha512-KtGJTvMPJL6QynasbSMNvz7Onc5ejebY6NzuUvgrw6sNohNJDR/3J/0e016ocQwvEq79MNK4v4EsxNi9eMELtg==", "requires": { - "buffer": "4.9.1", + "buffer": "4.9.2", "events": "1.1.1", "ieee754": "1.1.13", - "jmespath": "0.15.0", + "jmespath": "0.16.0", "querystring": "0.2.0", "sax": "1.2.1", "url": "0.10.3", @@ -269,9 +271,9 @@ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "base64-js": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", - "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, "bcrypt-pbkdf": { "version": "1.0.2", @@ -340,7 +342,8 @@ "dependencies": { "ansi-regex": { "version": "5.0.0", - "resolved": "" + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" }, "ansi-styles": { "version": "4.2.1", @@ -444,9 +447,9 @@ "integrity": "sha512-kDuEzldR21lHciPQAIulLs1LZlCXdLziXI6Mb/TDkwXhb//UORJNPXgcRs2CuO4H0DcMkpfT3/ySsP3unoZjBg==" }, "buffer": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", - "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", "requires": { "base64-js": "^1.0.2", "ieee754": "^1.1.4", @@ -553,12 +556,27 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } } }, "charenc": { @@ -597,38 +615,13 @@ "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==" }, "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "requires": { - "ansi-regex": "^4.1.0" - } - } + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, "clone-response": { @@ -817,9 +810,9 @@ } }, "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==" }, "decompress-response": { "version": "5.0.0", @@ -882,6 +875,15 @@ "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==" }, + "dezalgo": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", + "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", + "requires": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, "dicer": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", @@ -915,9 +917,9 @@ } }, "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==" }, "dot-prop": { "version": "5.3.0", @@ -964,9 +966,9 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "encodeurl": { "version": "1.0.2", @@ -981,6 +983,11 @@ "once": "^1.4.0" } }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, "escape-goat": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", @@ -1001,11 +1008,6 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" - }, "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -1072,9 +1074,22 @@ "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==" }, "formidable": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.2.tgz", - "integrity": "sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.0.1.tgz", + "integrity": "sha512-rjTMNbp2BpfQShhFbR3Ruk3qk2y9jKpvMW78nJgx8QKtxjDVrwbZG+wvDOmVbifHyOUOQJXxqEy6r0faRrPzTQ==", + "requires": { + "dezalgo": "1.0.3", + "hexoid": "1.0.0", + "once": "1.4.0", + "qs": "6.9.3" + }, + "dependencies": { + "qs": { + "version": "6.9.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.3.tgz", + "integrity": "sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw==" + } + } }, "fresh": { "version": "0.5.2", @@ -1134,9 +1149,9 @@ } }, "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -1232,6 +1247,11 @@ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" }, + "hexoid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", + "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==" + }, "hpack.js": { "version": "2.1.6", "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", @@ -1293,13 +1313,31 @@ } }, "http-signature": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.5.tgz", - "integrity": "sha512-NwoTQYSJoFt34jSBbwzDHDofoA61NGXzu6wXh95o1Ry62EnmKjXb/nR/RknLeZ3G/uGwrlKNY2z7uPt+Cdl7Tw==", + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", + "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", "requires": { "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", + "jsprim": "^2.0.2", "sshpk": "^1.14.1" + }, + "dependencies": { + "json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, + "jsprim": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", + "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + } } }, "http2-wrapper": { @@ -1385,9 +1423,9 @@ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" }, "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" }, "is-glob": { "version": "4.0.1", @@ -1445,6 +1483,11 @@ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==" + }, "is-yarn-global": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", @@ -1461,17 +1504,16 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" }, "jmespath": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", - "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", + "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==" }, "js-yaml": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", - "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" } }, "jsbn": { @@ -1484,11 +1526,6 @@ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" - }, "json5": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/json5/-/json5-0.4.0.tgz", @@ -1518,17 +1555,6 @@ } } }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, "jwa": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", @@ -1618,11 +1644,12 @@ "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" }, "log-symbols": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", - "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "requires": { - "chalk": "^4.0.0" + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" } }, "lowercase-keys": { @@ -1729,61 +1756,90 @@ } }, "mocha": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.2.1.tgz", - "integrity": "sha512-cuLBVfyFfFqbNR0uUKbDGXKGk+UDFe6aR4os78XIrMQpZl/nv7JYHcvP5MFIAb374b2zFXsdgEGwmzMtP0Xg8w==", + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.1.tgz", + "integrity": "sha512-T7uscqjJVS46Pq1XDXyo9Uvey9gd3huT/DD9cYBb4K2Xc/vbKRPUWK067bxDQRK0yIz6Jxk73IrnimvASzBNAQ==", "requires": { "@ungap/promise-all-settled": "1.1.2", "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", - "chokidar": "3.4.3", - "debug": "4.2.0", - "diff": "4.0.2", + "chokidar": "3.5.3", + "debug": "4.3.3", + "diff": "5.0.0", "escape-string-regexp": "4.0.0", "find-up": "5.0.0", - "glob": "7.1.6", + "glob": "7.2.0", "growl": "1.10.5", "he": "1.2.0", - "js-yaml": "3.14.0", - "log-symbols": "4.0.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", "minimatch": "3.0.4", - "ms": "2.1.2", - "nanoid": "3.1.12", - "serialize-javascript": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.2.0", + "serialize-javascript": "6.0.0", "strip-json-comments": "3.1.1", - "supports-color": "7.2.0", + "supports-color": "8.1.1", "which": "2.0.2", - "wide-align": "1.1.3", - "workerpool": "6.0.2", - "yargs": "13.3.2", - "yargs-parser": "13.1.2", + "workerpool": "6.2.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", "yargs-unparser": "2.0.0" }, "dependencies": { + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, "chokidar": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", - "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "requires": { - "anymatch": "~3.1.1", + "anymatch": "~3.1.2", "braces": "~3.0.2", - "fsevents": "~2.1.2", - "glob-parent": "~5.1.0", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", - "readdirp": "~3.5.0" + "readdirp": "~3.6.0" } }, + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "requires": { + "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true + }, "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "readdirp": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", - "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "requires": { "picomatch": "^2.2.1" } @@ -1940,9 +1996,9 @@ "optional": true }, "nanoid": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.12.tgz", - "integrity": "sha512-1qstj9z5+x491jfiC4Nelk+f8XBad7LN20PmyWINJEMRSf3wcAjAWysw1qaA8z6NSKe2sjq1hRSDpBH5paCb6A==" + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", + "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==" }, "ncp": { "version": "2.0.0", @@ -2083,11 +2139,6 @@ "p-limit": "^3.0.2" } }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - }, "package-json": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", @@ -2259,9 +2310,9 @@ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "pathval": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", - "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==" }, "pause": { "version": "0.0.1", @@ -2419,11 +2470,6 @@ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" - }, "require_optional": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", @@ -2480,6 +2526,11 @@ "vasync": "^2.2.0" }, "dependencies": { + "formidable": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.6.tgz", + "integrity": "sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==" + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -2636,18 +2687,13 @@ } }, "serialize-javascript": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", - "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", "requires": { "randombytes": "^2.1.0" } }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, "setprototypeof": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", @@ -2714,11 +2760,6 @@ } } }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" - }, "sshpk": { "version": "1.16.1", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", @@ -2751,12 +2792,13 @@ "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" }, "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" } }, "string_decoder": { @@ -2775,11 +2817,11 @@ } }, "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^5.0.1" } }, "strip-json-comments": { @@ -2788,9 +2830,9 @@ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" }, "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "requires": { "has-flag": "^4.0.0" }, @@ -2990,9 +3032,9 @@ "integrity": "sha512-mV5E0AG/F2yPiJzYlhyooI83BLIV0i4h/ueZwdxr1Mh8ZeKKpcFZLbZbAAedL/PLd11sqIgppJBrb4SNXA0PMQ==" }, "validator": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-8.2.0.tgz", - "integrity": "sha512-Yw5wW34fSv5spzTXNkokD6S6/Oq92d8q/t14TqsS3fAiA1RYnxSFSIZ+CY3n6PGGRCq5HhJTSepQvFUS2QUDxA==" + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz", + "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==" }, "vasync": { "version": "2.2.0", @@ -3028,19 +3070,6 @@ "isexe": "^2.0.0" } }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" - }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "requires": { - "string-width": "^1.0.2 || 2" - } - }, "widest-line": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", @@ -3051,7 +3080,8 @@ "dependencies": { "ansi-regex": { "version": "5.0.0", - "resolved": "" + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" }, "emoji-regex": { "version": "8.0.0", @@ -3084,64 +3114,18 @@ } }, "workerpool": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.2.tgz", - "integrity": "sha512-DSNyvOpFKrNusaaUwk+ej6cBj1bmhLcBfj80elGk+ZIo5JSkq+unB1dLKEOcNfJDZgjGICfhQ0Q5TbP0PvF4+Q==" + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", + "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==" }, "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "requires": { - "ansi-regex": "^4.1.0" - } - } + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" } }, "wrappy": { @@ -3185,9 +3169,9 @@ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" }, "y18n": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", - "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==" + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" }, "yallist": { "version": "3.1.1", @@ -3195,93 +3179,23 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "requires": { - "p-limit": "^2.0.0" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "requires": { - "ansi-regex": "^4.1.0" - } - } + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" } }, "yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==" }, "yargs-unparser": { "version": "2.0.0", @@ -3295,14 +3209,9 @@ }, "dependencies": { "camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==" - }, - "decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==" + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" } } }, diff --git a/package.json b/package.json index 8bca1972..f395d04e 100644 --- a/package.json +++ b/package.json @@ -27,19 +27,20 @@ "dependencies": { "agenda": "~4.1.3", "async": "2.4.1", - "aws-sdk": "~2.644.0", + "aws-sdk": "~2.1088.0", "chai": "~4.2.0", "config": "~1.20.4", "cron-parser": "~3.5.0", "debug": "^4.1.0", "extend": "~3.0.0", + "formidable": "~2.0.1", "got": "~11.0.2", "graphlib": "~2.1.1", "jsonwebtoken": "~8.5.1", "lodash": "~4.17.21", "md5": "~2.1.0", "mime": "~2.4.4", - "mocha": "~8.2.1", + "mocha": "~9.2.1", "moment": "~2.24.0", "mongoose": "~5.12.3", "mongoose-lifecycle": "1.0.0", @@ -55,6 +56,6 @@ "stream-buffers": "~2.2.0", "uuid": "~8.3.0", "valid-data-url": "~4.0.0", - "validator": "8.2.0" + "validator": "~13.7.0" } }