From a5d874c70cfa7307f913c43d36eefc5b3089c18b Mon Sep 17 00:00:00 2001 From: Ben Irvin Date: Thu, 24 Nov 2022 09:18:24 +0100 Subject: [PATCH 1/7] change file from arg to option --- packages/core/strapi/bin/strapi.js | 15 +++++++++++---- .../core/strapi/lib/commands/transfer/export.js | 4 +++- .../core/strapi/lib/commands/transfer/import.js | 11 +++-------- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/packages/core/strapi/bin/strapi.js b/packages/core/strapi/bin/strapi.js index 55aebc7e99..d87079de72 100755 --- a/packages/core/strapi/bin/strapi.js +++ b/packages/core/strapi/bin/strapi.js @@ -285,7 +285,9 @@ program .default(true) .argParser(parseInputBool) ) - .addOption(new Option('--key', 'Provide encryption key in command instead of using a prompt')) + .addOption( + new Option('--key ', 'Provide encryption key in command instead of using a prompt') + ) .addOption( new Option('--max-size ', 'split final file when exceeding size in MB') ) @@ -295,8 +297,8 @@ program 'split internal jsonl files when exceeding max size in MB' ) ) + .addOption(new Option('-f, --file ', 'name to use for exported file (without extensions)')) .addOption(excludeOption) - .arguments('[filename]') .allowExcessArguments(false) .hook('preAction', promptEncryptionKey) .action(getLocalScript('transfer/export')); @@ -321,9 +323,14 @@ program .default('exact') ) .addOption( - new Option('--key [encryptionKey]', 'prompt for [or provide directly] the decryption key') + new Option('--key ', 'Provide encryption key in command instead of using a prompt') + ) + .addOption( + new Option( + '-f, --file ', + 'path and filename to the Strapi export file you want to import' + ) ) - .arguments('') .allowExcessArguments(false) .hook( 'preAction', diff --git a/packages/core/strapi/lib/commands/transfer/export.js b/packages/core/strapi/lib/commands/transfer/export.js index 4dc86db866..1b9c7b20cf 100644 --- a/packages/core/strapi/lib/commands/transfer/export.js +++ b/packages/core/strapi/lib/commands/transfer/export.js @@ -40,12 +40,14 @@ const logger = console; const BYTES_IN_MB = 1024 * 1024; -module.exports = async (filename, opts) => { +module.exports = async (opts) => { // validate inputs from Commander if (!_.isObject(opts)) { logger.error('Could not parse arguments'); process.exit(1); } + const filename = opts.file; + /** * From local Strapi instance */ diff --git a/packages/core/strapi/lib/commands/transfer/import.js b/packages/core/strapi/lib/commands/transfer/import.js index e9d48e75d2..2fdb8289ec 100644 --- a/packages/core/strapi/lib/commands/transfer/import.js +++ b/packages/core/strapi/lib/commands/transfer/import.js @@ -7,18 +7,13 @@ const { // TODO: we need to solve this issue with typescript modules // eslint-disable-next-line import/no-unresolved, node/no-missing-require } = require('@strapi/data-transfer'); -const _ = require('lodash/fp'); const strapi = require('../../index'); const logger = console; -module.exports = async (filename, opts) => { - // validate inputs from Commander - if (!_.isString(filename) || !_.isObject(opts)) { - logger.error('Could not parse arguments'); - process.exit(1); - } +module.exports = async (opts) => { + const filename = opts.file; /** * From strapi backup file @@ -59,7 +54,7 @@ module.exports = async (filename, opts) => { logger.log('Results:', result); process.exit(0); } catch (e) { - logger.log('Import process failed unexpectedly'); + logger.log(`Import process failed unexpectedly: ${e.message}`); process.exit(1); } }; From 47c9e154b5bedf3847ba9c9279c09311ba44c1be Mon Sep 17 00:00:00 2001 From: Ben Irvin Date: Thu, 24 Nov 2022 09:44:13 +0100 Subject: [PATCH 2/7] restore validation --- packages/core/strapi/lib/commands/transfer/import.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/core/strapi/lib/commands/transfer/import.js b/packages/core/strapi/lib/commands/transfer/import.js index 2fdb8289ec..746b065eec 100644 --- a/packages/core/strapi/lib/commands/transfer/import.js +++ b/packages/core/strapi/lib/commands/transfer/import.js @@ -7,12 +7,17 @@ const { // TODO: we need to solve this issue with typescript modules // eslint-disable-next-line import/no-unresolved, node/no-missing-require } = require('@strapi/data-transfer'); - +const { isObject } = require('lodash/fp'); const strapi = require('../../index'); const logger = console; module.exports = async (opts) => { + // validate inputs from Commander + if (!isObject(opts)) { + logger.error('Could not parse arguments'); + process.exit(1); + } const filename = opts.file; /** From 416442f9708c90cd3b75a17201ce6f43470b45ff Mon Sep 17 00:00:00 2001 From: Ben Irvin Date: Thu, 24 Nov 2022 09:44:50 +0100 Subject: [PATCH 3/7] prompt for key if not provided for an encrypted file --- packages/core/strapi/bin/strapi.js | 31 ++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/packages/core/strapi/bin/strapi.js b/packages/core/strapi/bin/strapi.js index d87079de72..acb873f3c0 100755 --- a/packages/core/strapi/bin/strapi.js +++ b/packages/core/strapi/bin/strapi.js @@ -8,6 +8,7 @@ const _ = require('lodash'); const resolveCwd = require('resolve-cwd'); const { yellow } = require('chalk'); const { Command, Option } = require('commander'); +const inquirer = require('inquirer'); const program = new Command(); @@ -322,16 +323,34 @@ program .choices(['exact', 'strict', 'subset', 'bypass']) .default('exact') ) + .requiredOption( + '-f, --file ', + 'path and filename to the Strapi export file you want to import' + ) .addOption( new Option('--key ', 'Provide encryption key in command instead of using a prompt') ) - .addOption( - new Option( - '-f, --file ', - 'path and filename to the Strapi export file you want to import' - ) - ) .allowExcessArguments(false) + .hook('preAction', async (thisCommand) => { + const opts = thisCommand.opts(); + + // check extension to guess if we should prompt for key + if (String(opts.file).endsWith('.enc')) { + if (!opts.key) { + const answers = await inquirer.prompt([ + { + type: 'password', + message: 'Please enter your decryption key', + name: 'key', + }, + ]); + if (!answers.key?.length) { + process.exit(0); + } + opts.key = answers.key; + } + } + }) .hook( 'preAction', confirmKeyValue( From 48b81b747df97feffa5648f3c733b4c6f81de28a Mon Sep 17 00:00:00 2001 From: Ben Irvin Date: Thu, 24 Nov 2022 11:12:01 +0100 Subject: [PATCH 4/7] close pipeline correctly --- .../local-file-destination-provider.ts | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/core/data-transfer/lib/providers/local-file-destination-provider.ts b/packages/core/data-transfer/lib/providers/local-file-destination-provider.ts index e684e53304..c1d93a6665 100644 --- a/packages/core/data-transfer/lib/providers/local-file-destination-provider.ts +++ b/packages/core/data-transfer/lib/providers/local-file-destination-provider.ts @@ -56,7 +56,7 @@ class LocalFileDestinationProvider implements IDestinationProvider { results: ILocalFileDestinationProviderTransferResults = {}; #providersMetadata: { source?: IMetadata; destination?: IMetadata } = {}; - #archive: { stream?: tar.Pack } = {}; + #archive: { stream?: tar.Pack; pipeline?: Stream } = {}; constructor(options: ILocalFileDestinationProviderOptions) { this.options = options; @@ -117,25 +117,30 @@ class LocalFileDestinationProvider implements IDestinationProvider { archiveTransforms.push(createEncryptionCipher(encryption.key)); } - chain([this.#archive.stream, ...archiveTransforms, outStream]); + this.#archive.pipeline = chain([this.#archive.stream, ...archiveTransforms, outStream]); this.results.file = { path: this.#archivePath }; } async close() { - const { stream } = this.#archive; + const { stream, pipeline } = this.#archive; if (!stream) { return; } await this.#writeMetadata(); - stream.finalize(); - if (!stream.closed) { + if (pipeline && !pipeline.closed) { await new Promise((resolve, reject) => { - stream.on('close', resolve).on('error', reject); + pipeline + .on('close', () => { + resolve(); + }) + .on('error', (e) => { + reject(e); + }); }); } } From c0b321c64e8012db1a372cd4018e148910ab543f Mon Sep 17 00:00:00 2001 From: Ben Irvin Date: Thu, 24 Nov 2022 11:18:02 +0100 Subject: [PATCH 5/7] refactor --- .../lib/providers/local-file-destination-provider.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/packages/core/data-transfer/lib/providers/local-file-destination-provider.ts b/packages/core/data-transfer/lib/providers/local-file-destination-provider.ts index c1d93a6665..74c54f9c82 100644 --- a/packages/core/data-transfer/lib/providers/local-file-destination-provider.ts +++ b/packages/core/data-transfer/lib/providers/local-file-destination-provider.ts @@ -134,13 +134,7 @@ class LocalFileDestinationProvider implements IDestinationProvider { if (pipeline && !pipeline.closed) { await new Promise((resolve, reject) => { - pipeline - .on('close', () => { - resolve(); - }) - .on('error', (e) => { - reject(e); - }); + pipeline.on('close', resolve).on('error', resolve); }); } } From 605647c5e49eb91b52840abbef5932c2edf82221 Mon Sep 17 00:00:00 2001 From: Ben Irvin Date: Thu, 24 Nov 2022 11:21:49 +0100 Subject: [PATCH 6/7] add message --- packages/core/strapi/bin/strapi.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/core/strapi/bin/strapi.js b/packages/core/strapi/bin/strapi.js index acb873f3c0..a9e09af01f 100755 --- a/packages/core/strapi/bin/strapi.js +++ b/packages/core/strapi/bin/strapi.js @@ -345,6 +345,7 @@ program }, ]); if (!answers.key?.length) { + console.log('No key entered, aborting import.'); process.exit(0); } opts.key = answers.key; From de02ba208f860af4e28fad6ca86a928f808f043d Mon Sep 17 00:00:00 2001 From: Ben Irvin Date: Thu, 24 Nov 2022 11:34:05 +0100 Subject: [PATCH 7/7] fix reject --- .../lib/providers/local-file-destination-provider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/data-transfer/lib/providers/local-file-destination-provider.ts b/packages/core/data-transfer/lib/providers/local-file-destination-provider.ts index 74c54f9c82..756663fd0e 100644 --- a/packages/core/data-transfer/lib/providers/local-file-destination-provider.ts +++ b/packages/core/data-transfer/lib/providers/local-file-destination-provider.ts @@ -134,7 +134,7 @@ class LocalFileDestinationProvider implements IDestinationProvider { if (pipeline && !pipeline.closed) { await new Promise((resolve, reject) => { - pipeline.on('close', resolve).on('error', resolve); + pipeline.on('close', resolve).on('error', reject); }); } }