diff --git a/dashboard/public/js/client.js b/dashboard/public/js/client.js index 2a9690b6a..ab897d013 100644 --- a/dashboard/public/js/client.js +++ b/dashboard/public/js/client.js @@ -3678,6 +3678,9 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout var ACTION_APP_STOP = 'app.stop'; var ACTION_APP_RESTART = 'app.restart'; + var ACTION_ARCHIVES_ADD = 'archives.add'; + var ACTION_ARCHIVES_DEL = 'archives.del'; + var ACTION_BACKUP_FINISH = 'backup.finish'; var ACTION_BACKUP_START = 'backup.start'; var ACTION_BACKUP_CLEANUP_START = 'backup.cleanup.start'; @@ -3933,6 +3936,12 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout if (!data.app) return ''; return appName('', data.app, 'App') + ' was restarted'; + case ACTION_ARCHIVES_ADD: + return 'Backup ' + data.backupId + ' added to archive'; + + case ACTION_ARCHIVES_DEL: + return 'Backup ' + data.backupId + ' deleted from archive'; + case ACTION_BACKUP_START: return 'Backup started'; diff --git a/src/apps.js b/src/apps.js index 215d0f4c3..399071f2c 100644 --- a/src/apps.js +++ b/src/apps.js @@ -2496,8 +2496,8 @@ async function archive(app, backupId, auditSource) { if (result[0].id !== backupId) throw new BoxError(BoxError.BAD_STATE, 'Latest backup id has changed'); const icons = await getIcons(app.id); + await archives.add(backupId, { icon: icons.icon, appStoreIcon: icons.appStoreIcon, appConfig: app }, auditSource); const { taskId } = await uninstall(app, auditSource); - await archives.add(backupId, { icon: icons.icon, appStoreIcon: icons.appStoreIcon, appConfig: app }); return { taskId }; } diff --git a/src/archives.js b/src/archives.js index c0c0c3539..8c18a7db0 100644 --- a/src/archives.js +++ b/src/archives.js @@ -12,6 +12,7 @@ exports = module.exports = { const assert = require('assert'), BoxError = require('./boxerror.js'), database = require('./database.js'), + eventlog = require('./eventlog.js'), safe = require('safetydance'), uuid = require('uuid'); @@ -56,10 +57,11 @@ async function getIcon(id, options) { return null; } -async function add(backupId, data) { +async function add(backupId, data, auditSource) { assert.strictEqual(typeof backupId, 'string'); assert.strictEqual(typeof data, 'object'); assert(data.appConfig && typeof data.appConfig === 'object'); + assert(auditSource && typeof auditSource === 'object'); const id = uuid.v4(); @@ -70,6 +72,8 @@ async function add(backupId, data) { if (error && error.code === 'ER_DUP_ENTRY') throw new BoxError(BoxError.ALREADY_EXISTS, 'Archive already exists'); if (error) throw error; + await eventlog.add(eventlog.ACTION_ARCHIVES_ADD, auditSource, { id, backupId }); + return id; } @@ -89,10 +93,12 @@ async function listBackupIds() { return results.map(r => r.backupId); } -async function del(id, auditSource) { - assert.strictEqual(typeof id, 'string'); +async function del(archive, auditSource) { + assert.strictEqual(typeof archive, 'object'); assert(auditSource && typeof auditSource === 'object'); - const result = await database.query('DELETE FROM archives WHERE id=?', [ id ]); + const result = await database.query('DELETE FROM archives WHERE id=?', [ archive.id ]); if (result.affectedRows !== 1) throw new BoxError(BoxError.NOT_FOUND, 'No such archive'); + + await eventlog.add(eventlog.ACTION_ARCHIVES_DEL, auditSource, { id: archive.id, backupId: archive.backupId }); } diff --git a/src/eventlog.js b/src/eventlog.js index a209e9beb..930543dd9 100644 --- a/src/eventlog.js +++ b/src/eventlog.js @@ -30,6 +30,9 @@ exports = module.exports = { ACTION_APP_STOP: 'app.stop', ACTION_APP_RESTART: 'app.restart', + ACTION_ARCHIVES_ADD: 'archives.add', + ACTION_ARCHIVES_DEL: 'archives.del', + ACTION_BACKUP_FINISH: 'backup.finish', ACTION_BACKUP_START: 'backup.start', ACTION_BACKUP_CLEANUP_START: 'backup.cleanup.start', // obsolete diff --git a/src/routes/archives.js b/src/routes/archives.js index 2abe2a6d2..ddfe771cf 100644 --- a/src/routes/archives.js +++ b/src/routes/archives.js @@ -59,8 +59,9 @@ async function getIcon(req, res, next) { async function del(req, res, next) { assert.strictEqual(typeof req.params.id, 'string'); + assert.strictEqual(typeof req.resource, 'object'); - const [error] = await safe(archives.del(req.resource.id, AuditSource.fromRequest(req))); + const [error] = await safe(archives.del(req.resource, AuditSource.fromRequest(req))); if (error) return next(BoxError.toHttpError(error)); next(new HttpSuccess(204)); diff --git a/src/routes/test/archives-test.js b/src/routes/test/archives-test.js index 6e139e2fa..9ba1632d6 100644 --- a/src/routes/test/archives-test.js +++ b/src/routes/test/archives-test.js @@ -12,7 +12,7 @@ const archives = require('../../archives.js'), superagent = require('superagent'); describe('Archives API', function () { - const { setup, cleanup, serverUrl, owner } = common; + const { setup, cleanup, serverUrl, owner, auditSource } = common; const appBackup = { id: null, @@ -35,7 +35,7 @@ describe('Archives API', function () { before(async function () { await setup(); appBackup.id = await backups.add(appBackup); - archiveId = await archives.add(appBackup.id, { appConfig }); + archiveId = await archives.add(appBackup.id, { appConfig }, auditSource); }); after(cleanup); diff --git a/src/routes/test/common.js b/src/routes/test/common.js index 5b3c21ab7..ddfbcacb3 100644 --- a/src/routes/test/common.js +++ b/src/routes/test/common.js @@ -56,6 +56,8 @@ exports = module.exports = { mailFqdn: 'my.test.example.com', serverUrl: `http://localhost:${constants.PORT}`, + + auditSource: { ip: '5.6.7.8' } }; async function setupServer() { diff --git a/src/test/archives-test.js b/src/test/archives-test.js index 9e1bbbfed..026ac1b36 100644 --- a/src/test/archives-test.js +++ b/src/test/archives-test.js @@ -40,12 +40,12 @@ describe('Archives', function () { let archiveId; it('cannot add bad backup to archives', async function () { - const [error] = await safe(archives.add('badId', { appConfig })); + const [error] = await safe(archives.add('badId', { appConfig }, auditSource)); expect(error.reason).to.be(BoxError.NOT_FOUND); }); it('can add good backup to archives', async function () { - archiveId = await archives.add(appBackup.id, { appConfig }); + archiveId = await archives.add(appBackup.id, { appConfig }, auditSource); }); it('cannot get invalid archive', async function () { @@ -72,12 +72,12 @@ describe('Archives', function () { }); it('cannot delete bad archive', async function () { - const [error] = await safe(archives.del('badId', auditSource)); + const [error] = await safe(archives.del({ id: 'badId' }, auditSource)); expect(error.reason).to.be(BoxError.NOT_FOUND); }); it('can del valid archive', async function () { - await archives.del(archiveId, auditSource); + await archives.del({ id: archiveId }, auditSource); const result = await archives.list(1, 10); expect(result.length).to.be(0); }); diff --git a/src/test/backupcleaner-test.js b/src/test/backupcleaner-test.js index 8fd7b7b9a..9ff734263 100644 --- a/src/test/backupcleaner-test.js +++ b/src/test/backupcleaner-test.js @@ -271,7 +271,7 @@ describe('backup cleaner', function () { BACKUP_1_BOX.id = await backups.add(BACKUP_1_BOX); BACKUP_2_APP_2.id = await backups.add(BACKUP_2_APP_2); - await archives.add(BACKUP_2_APP_2.id, { appConfig: app2Config }); + await archives.add(BACKUP_2_APP_2.id, { appConfig: app2Config }, common.auditSource); }); it('succeeds with box backups, keeps latest', async function () {