diff --git a/src/eventlog.js b/src/eventlog.js index 4881523bd..4c17cac06 100644 --- a/src/eventlog.js +++ b/src/eventlog.js @@ -7,17 +7,20 @@ exports = module.exports = { get: get, getAllPaged: getAllPaged, - ACTION_ACTIVATED: 'box.activated', + ACTION_ACTIVATE: 'cloudron.activate', ACTION_APP_CONFIGURE: 'app.configure', ACTION_APP_INSTALL: 'app.install', ACTION_APP_RESTORE: 'app.restore', ACTION_APP_UNINSTALL: 'app.uninstall', ACTION_APP_UPDATE: 'app.update', - ACTION_BACKUP_STARTED: 'backup.started', - ACTION_BACKUP_DONE: 'backup.done', - ACTION_BOX_REBOOT: 'box.reboot', + ACTION_BACKUP: 'cloudron.backup', ACTION_CLI_MODE: 'settings.climode', - ACTION_UPDATE: 'box.update' + ACTION_PROFILE: 'user.profile', + ACTION_REBOOT: 'cloudron.reboot', + ACTION_UPDATE: 'cloudron.update', + ACTION_USER_ADD: 'user.add', + ACTION_USER_REMOVE: 'user.remove', + ACTION_USER_UPDATE: 'user.update' }; var assert = require('assert'), @@ -51,15 +54,17 @@ util.inherits(EventLogError, Error); EventLogError.INTERNAL_ERROR = 'Internal error'; EventLogError.NOT_FOUND = 'Not Found'; -function add(action, source, data, callback) { +function add(action, req, data, callback) { assert.strictEqual(typeof action, 'string'); - assert.strictEqual(typeof source, 'object'); + assert.strictEqual(typeof req, 'object'); assert.strictEqual(typeof data, 'object'); assert(!callback || typeof callback === 'function'); callback = callback || NOOP_CALLBACK; var id = uuid.v4(); + var source = { ip: req.ip || null, username: req.user ? req.user.username : null }; + eventlogdb.add(id, action, source, data, function (error) { if (error) return callback(new EventLogError(EventLogError.INTERNAL_ERROR, error)); diff --git a/src/routes/apps.js b/src/routes/apps.js index 511364fd4..7f628afd3 100644 --- a/src/routes/apps.js +++ b/src/routes/apps.js @@ -24,6 +24,7 @@ var apps = require('../apps.js'), AppsError = apps.AppsError, assert = require('assert'), debug = require('debug')('box:routes/apps'), + eventlog = require('../eventlog.js'), fs = require('fs'), HttpError = require('connect-lastmile').HttpError, HttpSuccess = require('connect-lastmile').HttpSuccess, @@ -142,6 +143,8 @@ function installApp(req, res, next) { if (error && error.reason === AppsError.USER_REQUIRED) return next(new HttpError(400, 'accessRestriction must specify one user')); if (error) return next(new HttpError(500, error)); + eventlog.add(eventlog.ACTION_APP_INSTALL, req, { id: appId, location: data.location, manifest: data.manifest }); + next(new HttpSuccess(202, { id: appId } )); }); } @@ -182,6 +185,8 @@ function configureApp(req, res, next) { if (error && error.reason === AppsError.BAD_CERTIFICATE) return next(new HttpError(400, error.message)); if (error) return next(new HttpError(500, error)); + eventlog.add(eventlog.ACTION_APP_CONFIGURE, req, { id: req.params.id, location: data.location }); + next(new HttpSuccess(202, { })); }); } @@ -197,6 +202,8 @@ function restoreApp(req, res, next) { if (error && error.reason === AppsError.BAD_STATE) return next(new HttpError(409, error.message)); if (error) return next(new HttpError(500, error)); + eventlog.add(eventlog.ACTION_APP_RESTORE, req, { id: req.params.id }); + next(new HttpSuccess(202, { })); }); } @@ -229,6 +236,8 @@ function uninstallApp(req, res, next) { if (error && error.reason === AppsError.NOT_FOUND) return next(new HttpError(404, 'No such app')); if (error) return next(new HttpError(500, error)); + eventlog.add(eventlog.ACTION_APP_UNINSTALL, req, { id: req.params.id }); + next(new HttpSuccess(202, { })); }); } diff --git a/src/routes/backups.js b/src/routes/backups.js index 27584e022..a7164973f 100644 --- a/src/routes/backups.js +++ b/src/routes/backups.js @@ -9,6 +9,7 @@ exports = module.exports = { var assert = require('assert'), backups = require('../backups.js'), BackupsError = require('../backups.js').BackupsError, + eventlog = require('../eventlog.js'), HttpError = require('connect-lastmile').HttpError, HttpSuccess = require('connect-lastmile').HttpSuccess; @@ -34,6 +35,8 @@ function create(req, res, next) { if (error && error.reason === BackupsError.BAD_STATE) return next(new HttpError(409, error.message)); if (error) return next(new HttpError(500, error)); + eventlog.add(eventlog.ACTION_BACKUP, req, { }); + next(new HttpSuccess(202, {})); }); } diff --git a/src/routes/cloudron.js b/src/routes/cloudron.js index 8a9f51b72..d3e5e8516 100644 --- a/src/routes/cloudron.js +++ b/src/routes/cloudron.js @@ -13,13 +13,14 @@ exports = module.exports = { var assert = require('assert'), cloudron = require('../cloudron.js'), - config = require('../config.js'), - progress = require('../progress.js'), - mailer = require('../mailer.js'), CloudronError = cloudron.CloudronError, + config = require('../config.js'), debug = require('debug')('box:routes/cloudron'), + eventlog = require('../eventlog.js'), HttpError = require('connect-lastmile').HttpError, HttpSuccess = require('connect-lastmile').HttpSuccess, + progress = require('../progress.js'), + mailer = require('../mailer.js'), superagent = require('superagent'); /** @@ -55,6 +56,8 @@ function activate(req, res, next) { if (error && error.reason === CloudronError.BAD_EMAIL) return next(new HttpError(400, 'Bad email')); if (error) return next(new HttpError(500, error)); + eventlog.add(eventlog.ACTION_ACTIVATE, req, { }); + // only in caas case do we have to notify the api server about activation if (config.provider() !== 'caas') return next(new HttpSuccess(201, info)); @@ -104,6 +107,8 @@ function reboot(req, res, next) { // Finish the request, to let the appstore know we triggered the restore it next(new HttpSuccess(202, {})); + eventlog.add(eventlog.ACTION_REBOOT, req, { }); + cloudron.reboot(); } @@ -122,6 +127,8 @@ function update(req, res, next) { if (error && error.reason === CloudronError.BAD_STATE) return next(new HttpError(409, error.message)); if (error) return next(new HttpError(500, error)); + eventlog.add(eventlog.ACTION_UPDATE, req, { }); + next(new HttpSuccess(202, {})); }); } diff --git a/src/routes/developer.js b/src/routes/developer.js index 0345abb8b..f59de9205 100644 --- a/src/routes/developer.js +++ b/src/routes/developer.js @@ -9,6 +9,7 @@ exports = module.exports = { }; var developer = require('../developer.js'), + eventlog = require('../eventlog.js'), passport = require('passport'), HttpError = require('connect-lastmile').HttpError, HttpSuccess = require('connect-lastmile').HttpSuccess; @@ -25,6 +26,9 @@ function setEnabled(req, res, next) { developer.setEnabled(req.body.enabled, function (error) { if (error) return next(new HttpError(500, error)); + + eventlog.add(eventlog.ACTION_CLI_MODE, req, { enabled: req.body.enabled }); + next(new HttpSuccess(200, {})); }); } diff --git a/src/routes/profile.js b/src/routes/profile.js index 006bf9a93..fb3c9020d 100644 --- a/src/routes/profile.js +++ b/src/routes/profile.js @@ -7,6 +7,7 @@ exports = module.exports = { }; var assert = require('assert'), + eventlog = require('../eventlog.js'), groups = require('../groups.js'), HttpError = require('connect-lastmile').HttpError, HttpSuccess = require('connect-lastmile').HttpSuccess, @@ -54,6 +55,8 @@ function update(req, res, next) { if (error && error.reason === UserError.NOT_FOUND) return next(new HttpError(404, 'User not found')); if (error) return next(new HttpError(500, error)); + eventlog.add(eventlog.ACTION_PROFILE, req, { }); + next(new HttpSuccess(204)); }); } diff --git a/src/routes/user.js b/src/routes/user.js index f274c2858..cb7bc3cfe 100644 --- a/src/routes/user.js +++ b/src/routes/user.js @@ -13,6 +13,7 @@ exports = module.exports = { }; var assert = require('assert'), + eventlog = require('../eventlog.js'), generatePassword = require('../password.js').generate, groups = require('../groups.js'), HttpError = require('connect-lastmile').HttpError, @@ -52,6 +53,8 @@ function create(req, res, next) { resetToken: user.resetToken }; + eventlog.add(eventlog.ACTION_USER_ADD, req, { id: user.id, username: user.username, sendInvite: sendInvite }); + next(new HttpSuccess(201, userInfo )); }); } @@ -78,6 +81,8 @@ function update(req, res, next) { if (error && error.reason === UserError.NOT_FOUND) return next(new HttpError(404, 'User not found')); if (error) return next(new HttpError(500, error)); + eventlog.add(eventlog.ACTION_USER_UPDATE, req, { id: req.params.userId, username: result.username }); + next(new HttpSuccess(204)); }); }); @@ -132,6 +137,8 @@ function remove(req, res, next) { if (error && error.reason === UserError.NOT_FOUND) return next(new HttpError(404, 'No such user')); if (error) return next(new HttpError(500, error)); + eventlog.add(eventlog.ACTION_USER_REMOVE, req, { id: req.params.userId, username: userObject.username }); + next(new HttpSuccess(204)); }); }); diff --git a/src/test/eventlog-test.js b/src/test/eventlog-test.js index f25adf23f..5df3139c4 100644 --- a/src/test/eventlog-test.js +++ b/src/test/eventlog-test.js @@ -47,7 +47,7 @@ describe('Eventlog', function () { expect(result.action).to.be('some.event'); expect(result.creationTime).to.be.a(Date); - expect(result.source).to.be.eql({ ip: '1.2.3.4' }); + expect(result.source).to.be.eql({ ip: '1.2.3.4', username: null }); expect(result.data).to.be.eql({ appId: 'thatapp' }); done(); @@ -72,7 +72,7 @@ describe('Eventlog', function () { expect(results[0].id).to.be(eventId); expect(results[0].action).to.be('some.event'); - expect(results[0].source).to.be.eql({ ip: '1.2.3.4' }); + expect(results[0].source).to.be.eql({ ip: '1.2.3.4', username: null }); expect(results[0].data).to.be.eql({ appId: 'thatapp' }); done();