diff --git a/src/asyncif.js b/src/asyncif.js deleted file mode 100644 index dad475939..000000000 --- a/src/asyncif.js +++ /dev/null @@ -1,16 +0,0 @@ -'use strict'; - -exports = module.exports = asyncIf; - -let assert = require('assert'); - -function asyncIf(condition, func, callback) { - assert.strictEqual(typeof condition, 'boolean'); - assert.strictEqual(typeof func, 'function'); - assert.strictEqual(typeof callback, 'function'); - - if (!condition) return callback(); - - func(callback); -} - diff --git a/src/backups.js b/src/backups.js index d23e5c01e..6cbb11894 100644 --- a/src/backups.js +++ b/src/backups.js @@ -26,6 +26,11 @@ exports = module.exports = { cleanup: cleanup, cleanupCacheFilesSync: cleanupCacheFilesSync, + injectPrivateFields: injectPrivateFields, + removePrivateFields: removePrivateFields, + + SECRET_PLACEHOLDER: String.fromCharCode(0x25CF).repeat(8), + // for testing _getBackupFilePath: getBackupFilePath, _restoreFsMetadata: restoreFsMetadata, @@ -113,6 +118,17 @@ function api(provider) { } } +function injectPrivateFields(newConfig, currentConfig) { + if (newConfig.key === exports.SECRET_PLACEHOLDER) newConfig.key = currentConfig.key; + if (newConfig.provider === currentConfig.provider) api(newConfig.provider).injectPrivateFields(newConfig, currentConfig); +} + +function removePrivateFields(backupConfig) { + assert.strictEqual(typeof backupConfig, 'object'); + if (backupConfig.key) backupConfig.key = exports.SECRET_PLACEHOLDER; + return api(backupConfig.provider).removePrivateFields(backupConfig); +} + function testConfig(backupConfig, callback) { assert.strictEqual(typeof backupConfig, 'object'); assert.strictEqual(typeof callback, 'function'); diff --git a/src/routes/settings.js b/src/routes/settings.js index c19a223c8..40af03e5a 100644 --- a/src/routes/settings.js +++ b/src/routes/settings.js @@ -32,6 +32,7 @@ exports = module.exports = { }; var assert = require('assert'), + backups = require('../backups.js'), docker = require('../docker.js'), DockerError = docker.DockerError, HttpError = require('connect-lastmile').HttpError, @@ -153,7 +154,7 @@ function getBackupConfig(req, res, next) { settings.getBackupConfig(function (error, config) { if (error) return next(new HttpError(500, error)); - next(new HttpSuccess(200, settings.removeBackupConfigPrivateFields(config))); + next(new HttpSuccess(200, backups.removePrivateFields(config))); }); } diff --git a/src/settings.js b/src/settings.js index bab8d9ad4..87ab3446b 100644 --- a/src/settings.js +++ b/src/settings.js @@ -23,7 +23,6 @@ exports = module.exports = { getBackupConfig: getBackupConfig, setBackupConfig: setBackupConfig, - removeBackupConfigPrivateFields: removeBackupConfigPrivateFields, getCaasConfig: getCaasConfig, @@ -60,7 +59,6 @@ exports = module.exports = { var addons = require('./addons.js'), assert = require('assert'), - asyncIf = require('./asyncif.js'), backups = require('./backups.js'), BackupsError = backups.BackupsError, config = require('./config.js'), @@ -294,13 +292,6 @@ function setDynamicDnsConfig(enabled, callback) { }); } -// removes fields that should not returned in API responses. keep in sync with setBackupConfig -function removeBackupConfigPrivateFields(backupConfig) { - var result = _.omit(backupConfig, (v, k) => k === 'token' || k === 'key' || k.toLowerCase().includes('secret')); - - return result; -} - function getBackupConfig(callback) { assert.strictEqual(typeof callback, 'function'); @@ -316,13 +307,12 @@ function setBackupConfig(backupConfig, callback) { assert.strictEqual(typeof backupConfig, 'object'); assert.strictEqual(typeof callback, 'function'); - // keep in sync with removeBackupConfigPrivateFields - const verifyConfig = Object.keys(backupConfig).some((k) => k === 'token' || k === 'key' || k.toLowerCase().includes('secret')); - getBackupConfig(function (error, curentConfig) { if (error) return callback(error); - asyncIf(verifyConfig, (done) => backups.testConfig(backupConfig, done), function (error) { + backups.injectPrivateFields(backupConfig, curentConfig); + + backups.testConfig(backupConfig, function (error) { if (error && error.reason === BackupsError.BAD_FIELD) return callback(new SettingsError(SettingsError.BAD_FIELD, error.message)); if (error && error.reason === BackupsError.EXTERNAL_ERROR) return callback(new SettingsError(SettingsError.EXTERNAL_ERROR, error.message)); if (error) return callback(new SettingsError(SettingsError.INTERNAL_ERROR, error)); diff --git a/src/storage/filesystem.js b/src/storage/filesystem.js index 9c64d46ce..925b0293f 100644 --- a/src/storage/filesystem.js +++ b/src/storage/filesystem.js @@ -11,7 +11,9 @@ exports = module.exports = { remove: remove, removeDir: removeDir, - testConfig: testConfig + testConfig: testConfig, + removePrivateFields: removePrivateFields, + injectPrivateFields: injectPrivateFields }; var assert = require('assert'), @@ -189,3 +191,9 @@ function testConfig(apiConfig, callback) { }); } +function removePrivateFields(apiConfig) { + return apiConfig; +} + +function injectPrivateFields(/* newConfig, currentConfig */) { +} diff --git a/src/storage/gcs.js b/src/storage/gcs.js index 1983d32f1..211cbd172 100644 --- a/src/storage/gcs.js +++ b/src/storage/gcs.js @@ -11,6 +11,8 @@ exports = module.exports = { removeDir: removeDir, testConfig: testConfig, + removePrivateFields: removePrivateFields, + injectPrivateFields: injectPrivateFields, // Used to mock GCS _mockInject: mockInject, @@ -19,6 +21,7 @@ exports = module.exports = { var assert = require('assert'), async = require('async'), + backups = require('../backups.js'), BackupsError = require('../backups.js').BackupsError, debug = require('debug')('box:storage/gcs'), EventEmitter = require('events'), @@ -258,3 +261,11 @@ function testConfig(apiConfig, callback) { }); } +function removePrivateFields(apiConfig) { + apiConfig.credentials.private_key = backups.SECRET_PLACEHOLDER; + return apiConfig; +} + +function injectPrivateFields(newConfig, currentConfig) { + if (newConfig.credentials.private_key === backups.SECRET_PLACEHOLDER && currentConfig.credentials) newConfig.credentials.private_key = currentConfig.credentials.private_key; +} diff --git a/src/storage/interface.js b/src/storage/interface.js index be24cba6f..11aed198d 100644 --- a/src/storage/interface.js +++ b/src/storage/interface.js @@ -22,12 +22,23 @@ exports = module.exports = { remove: remove, removeDir: removeDir, - testConfig: testConfig + testConfig: testConfig, + removePrivateFields: removePrivateFields, + injectPrivateFields: injectPrivateFields }; var assert = require('assert'), EventEmitter = require('events'); +function removePrivateFields(apiConfig) { + // in-place removal of tokens and api keys with domains.SECRET_PLACEHOLDER + return apiConfig; +} + +function injectPrivateFields(newConfig, currentConfig) { + // in-place injection of tokens and api keys which came in with domains.SECRET_PLACEHOLDER +} + function upload(apiConfig, backupFilePath, sourceStream, callback) { assert.strictEqual(typeof apiConfig, 'object'); assert.strictEqual(typeof backupFilePath, 'string'); diff --git a/src/storage/noop.js b/src/storage/noop.js index d6f7ecbbb..bb5073793 100644 --- a/src/storage/noop.js +++ b/src/storage/noop.js @@ -11,7 +11,9 @@ exports = module.exports = { remove: remove, removeDir: removeDir, - testConfig: testConfig + testConfig: testConfig, + removePrivateFields: removePrivateFields, + injectPrivateFields: injectPrivateFields }; var assert = require('assert'), @@ -103,3 +105,9 @@ function testConfig(apiConfig, callback) { callback(null); } +function removePrivateFields(apiConfig) { + return apiConfig; +} + +function injectPrivateFields(newConfig, currentConfig) { +} diff --git a/src/storage/s3.js b/src/storage/s3.js index 82b4db080..68e483bad 100644 --- a/src/storage/s3.js +++ b/src/storage/s3.js @@ -11,6 +11,8 @@ exports = module.exports = { removeDir: removeDir, testConfig: testConfig, + removePrivateFields: removePrivateFields, + injectPrivateFields: injectPrivateFields, // Used to mock AWS _mockInject: mockInject, @@ -20,6 +22,7 @@ exports = module.exports = { var assert = require('assert'), async = require('async'), AWS = require('aws-sdk'), + backups = require('../backups.js'), BackupsError = require('../backups.js').BackupsError, chunk = require('lodash.chunk'), config = require('../config.js'), @@ -48,10 +51,6 @@ function S3_NOT_FOUND(error) { return error.code === 'NoSuchKey' || error.code === 'NotFound' || error.code === 'ENOENT'; } -function S3_ACCESS_DENIED(error) { - return error.code === 'AccessDenied' || error.statusCode === 403; -} - function getCaasConfig(apiConfig, callback) { assert.strictEqual(typeof apiConfig, 'object'); assert.strictEqual(typeof callback, 'function'); @@ -486,3 +485,12 @@ function testConfig(apiConfig, callback) { }); }); } + +function removePrivateFields(apiConfig) { + apiConfig.secretAccessKey = backups.SECRET_PLACEHOLDER; + return apiConfig; +} + +function injectPrivateFields(newConfig, currentConfig) { + if (newConfig.secretAccessKey === backups.SECRET_PLACEHOLDER) newConfig.secretAccessKey = currentConfig.secretAccessKey; +}