backups: make id, provider a backend specific setting
the backend can stash whatever values it wants in the config. just like the DNS backends, we make verifyConfig return a sanitized config. added benefit is that extra user fields (via API) are also not dumped into the db.
This commit is contained in:
@@ -5,7 +5,7 @@ exports = module.exports = {
|
||||
teardown,
|
||||
cleanup,
|
||||
|
||||
testConfig,
|
||||
verifyConfig,
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
|
||||
@@ -41,7 +41,8 @@ const assert = require('assert'),
|
||||
{ Readable } = require('stream'),
|
||||
{ S3, NoSuchKey, NoSuchBucket } = require('@aws-sdk/client-s3'),
|
||||
safe = require('safetydance'),
|
||||
{ Upload } = require('@aws-sdk/lib-storage');
|
||||
{ Upload } = require('@aws-sdk/lib-storage'),
|
||||
_ = require('../underscore.js');
|
||||
|
||||
function S3_NOT_FOUND(error) {
|
||||
return error instanceof NoSuchKey || error instanceof NoSuchBucket;
|
||||
@@ -567,39 +568,41 @@ async function cleanup(apiConfig, progressCallback) {
|
||||
}
|
||||
}
|
||||
|
||||
async function testConfig(apiConfig) {
|
||||
assert.strictEqual(typeof apiConfig, 'object');
|
||||
async function verifyConfig({ id, provider, config }) {
|
||||
assert.strictEqual(typeof id, 'string');
|
||||
assert.strictEqual(typeof provider, 'string');
|
||||
assert.strictEqual(typeof config, 'object');
|
||||
|
||||
if (typeof apiConfig.accessKeyId !== 'string') throw new BoxError(BoxError.BAD_FIELD, 'accessKeyId must be a string');
|
||||
if (typeof apiConfig.secretAccessKey !== 'string') throw new BoxError(BoxError.BAD_FIELD, 'secretAccessKey must be a string');
|
||||
if (typeof config.accessKeyId !== 'string') throw new BoxError(BoxError.BAD_FIELD, 'accessKeyId must be a string');
|
||||
if (typeof config.secretAccessKey !== 'string') throw new BoxError(BoxError.BAD_FIELD, 'secretAccessKey must be a string');
|
||||
|
||||
if (typeof apiConfig.bucket !== 'string') throw new BoxError(BoxError.BAD_FIELD, 'bucket must be a string');
|
||||
if (typeof config.bucket !== 'string') throw new BoxError(BoxError.BAD_FIELD, 'bucket must be a string');
|
||||
// the node module seems to incorrectly accept bucket name with '/'
|
||||
if (apiConfig.bucket.includes('/')) throw new BoxError(BoxError.BAD_FIELD, 'bucket name cannot contain "/"');
|
||||
if (config.bucket.includes('/')) throw new BoxError(BoxError.BAD_FIELD, 'bucket name cannot contain "/"');
|
||||
|
||||
// names must be lowercase and start with a letter or number. can contain dashes
|
||||
if (apiConfig.bucket.includes('_') || apiConfig.bucket.match(/[A-Z]/)) throw new BoxError(BoxError.BAD_FIELD, 'bucket name cannot contain "_" or capitals');
|
||||
if (config.bucket.includes('_') || config.bucket.match(/[A-Z]/)) throw new BoxError(BoxError.BAD_FIELD, 'bucket name cannot contain "_" or capitals');
|
||||
|
||||
if (typeof apiConfig.prefix !== 'string') throw new BoxError(BoxError.BAD_FIELD, 'prefix must be a string');
|
||||
if ('signatureVersion' in apiConfig && typeof apiConfig.signatureVersion !== 'string') throw new BoxError(BoxError.BAD_FIELD, 'signatureVersion must be a string');
|
||||
if ('endpoint' in apiConfig && typeof apiConfig.endpoint !== 'string') throw new BoxError(BoxError.BAD_FIELD, 'endpoint must be a string');
|
||||
if (typeof config.prefix !== 'string') throw new BoxError(BoxError.BAD_FIELD, 'prefix must be a string');
|
||||
if ('signatureVersion' in config && typeof config.signatureVersion !== 'string') throw new BoxError(BoxError.BAD_FIELD, 'signatureVersion must be a string');
|
||||
if ('endpoint' in config && typeof config.endpoint !== 'string') throw new BoxError(BoxError.BAD_FIELD, 'endpoint must be a string');
|
||||
|
||||
if ('acceptSelfSignedCerts' in apiConfig && typeof apiConfig.acceptSelfSignedCerts !== 'boolean') throw new BoxError(BoxError.BAD_FIELD, 'acceptSelfSignedCerts must be a boolean');
|
||||
if ('s3ForcePathStyle' in apiConfig && typeof apiConfig.s3ForcePathStyle !== 'boolean') throw new BoxError(BoxError.BAD_FIELD, 's3ForcePathStyle must be a boolean');
|
||||
if ('acceptSelfSignedCerts' in config && typeof config.acceptSelfSignedCerts !== 'boolean') throw new BoxError(BoxError.BAD_FIELD, 'acceptSelfSignedCerts must be a boolean');
|
||||
if ('s3ForcePathStyle' in config && typeof config.s3ForcePathStyle !== 'boolean') throw new BoxError(BoxError.BAD_FIELD, 's3ForcePathStyle must be a boolean');
|
||||
|
||||
const putParams = {
|
||||
Bucket: apiConfig.bucket,
|
||||
Key: path.join(apiConfig.prefix, 'snapshot/cloudron-testfile'),
|
||||
Bucket: config.bucket,
|
||||
Key: path.join(config.prefix, 'snapshot/cloudron-testfile'),
|
||||
Body: 'testcontent'
|
||||
};
|
||||
|
||||
const s3 = createS3Client(apiConfig, {});
|
||||
const s3 = createS3Client(config, {});
|
||||
const [putError] = await safe(s3.putObject(putParams));
|
||||
if (putError) throw new BoxError(BoxError.EXTERNAL_ERROR, `Error put object cloudron-testfile. ${formatError(putError)}`);
|
||||
|
||||
const listParams = {
|
||||
Bucket: apiConfig.bucket,
|
||||
Prefix: path.join(apiConfig.prefix, 'snapshot'),
|
||||
Bucket: config.bucket,
|
||||
Prefix: path.join(config.prefix, 'snapshot'),
|
||||
MaxKeys: 1
|
||||
};
|
||||
|
||||
@@ -607,12 +610,15 @@ async function testConfig(apiConfig) {
|
||||
if (listError) throw new BoxError(BoxError.EXTERNAL_ERROR, `Error listing objects. ${formatError(listError)}`);
|
||||
|
||||
const delParams = {
|
||||
Bucket: apiConfig.bucket,
|
||||
Key: path.join(apiConfig.prefix, 'snapshot/cloudron-testfile')
|
||||
Bucket: config.bucket,
|
||||
Key: path.join(config.prefix, 'snapshot/cloudron-testfile')
|
||||
};
|
||||
|
||||
const [delError] = await safe(s3.deleteObject(delParams));
|
||||
if (delError) throw new BoxError(BoxError.EXTERNAL_ERROR, `Error del object cloudron-testfile. ${formatError(delError)}`);
|
||||
|
||||
const newConfig = _.pick(config, ['accessKeyId', 'secretAccessKey', 'bucket', 'prefix', 'signatureVersion', 'acceptSelfSignedCerts', 'endpoint', 's3ForcePathStyle' ]);
|
||||
return { provider, ...newConfig };
|
||||
}
|
||||
|
||||
async function setup(apiConfig) {
|
||||
@@ -625,9 +631,11 @@ async function teardown(apiConfig) {
|
||||
|
||||
function removePrivateFields(apiConfig) {
|
||||
apiConfig.secretAccessKey = constants.SECRET_PLACEHOLDER;
|
||||
delete apiConfig.provider;
|
||||
return apiConfig;
|
||||
}
|
||||
|
||||
function injectPrivateFields(newConfig, currentConfig) {
|
||||
if (newConfig.secretAccessKey === constants.SECRET_PLACEHOLDER) newConfig.secretAccessKey = currentConfig.secretAccessKey;
|
||||
newConfig.provider = currentConfig.provider;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user