diff --git a/generator/cybersource_node_sdk_gen.bat b/generator/cybersource_node_sdk_gen.bat index d3cc34bc..c77f4233 100644 --- a/generator/cybersource_node_sdk_gen.bat +++ b/generator/cybersource_node_sdk_gen.bat @@ -26,6 +26,7 @@ git checkout ..\src\model\CreateAccessTokenRequest.js git checkout ..\src\model\BadRequestError.js git checkout ..\src\model\ResourceNotFoundError.js git checkout ..\src\model\UnauthorizedClientError.js +git checkout ..\src\api\BatchUploadWithMTLSApi.js git checkout ..\docs\OAuthApi.md git checkout ..\docs\AccessTokenResponse.md diff --git a/package.json b/package.json index 1c000e84..624a2ea1 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "jwt-simple": "^0.5.6", "memory-cache": "^0.2.0", "node-forge": ">=1.0.0", + "openpgp": "^6.1.1", "promise": "^8.3.0", "winston": "^3.11.0", "winston-daily-rotate-file": "^4.7.1", diff --git a/src/api/BatchUploadWithMTLSApi.js b/src/api/BatchUploadWithMTLSApi.js new file mode 100644 index 00000000..9b398afa --- /dev/null +++ b/src/api/BatchUploadWithMTLSApi.js @@ -0,0 +1,197 @@ +const path = require('path'); +const fs = require('fs'); +const PgpEncryptionUtility = require('../utilities/PGP/BatchUpload/PgpEncryptionUtility'); +const MutualAuthUploadUtility = require('../utilities/PGP/BatchUpload/MutualAuthUploadUtility'); +const BatchUploadUtility = require('../utilities/PGP/BatchUpload/BatchUploadUtility'); +const LogConfiguration = require('../authentication/logging/LogConfiguration'); +const Constants = require('../authentication/util/Constants'); +const Logger = require('../authentication/logging/Logger'); + +/** + * BatchUploadWithMTLSApi + * Class for uploading batch files to CyberSource using mutual TLS authentication. + * Supports PKCS#12 client certificates, and direct private key/certificate paths. + * Handles PGP encryption of files before upload. + */ +class BatchUploadWithMTLSApi { + /** + * Constructs a new BatchUploadWithMTLSApi instance. + * @param {Object} [log_config] - Logging configuration object (optional). + * @param {boolean} [log_config.enableLog=false] - Enable or disable logging. + * @param {string} [log_config.logFileName='cybs-batch-upload'] - Log file name (without extension). + * @param {string} [log_config.logDirectory='./logs'] - Directory to store log files. + * @param {number} [log_config.logFileMaxSize=5242880] - Maximum log file size in bytes (default 5MB). + * @param {string} [log_config.loggingLevel='debug'] - Logging level ('debug', 'info', 'warn', 'error'). + * + * Example: + * const log_config = { + * enableLog: true, + * logFileName: 'cybs-batch-upload', + * logDirectory: './logs', + * logFileMaxSize: 5242880, + * loggingLevel: 'debug' + * }; + */ + constructor(log_config) { + if (!log_config) { + log_config = { + enableLog: false + }; + } + const logConfiguration = new LogConfiguration(log_config); + //fallback for missing values + logConfiguration.getDefaultLoggingProperties(""); + + this.logger = Logger.getLoggerFromLogConfig(logConfiguration, 'BatchUploadWithMTLSApi'); + this.logger.info(Constants.BEGIN_TRANSACTION); + } + + /** + * Uploads a batch file to CyberSource using a PKCS#12 (.p12/.pfx) client certificate for mutual TLS authentication. + * The file is PGP-encrypted before upload. + * + * @param {Object} opts - Options for the upload. + * @param {string} opts.inputFilePath - Path to the input file to be uploaded. + * @param {string} opts.environmentHostname - CyberSource environment hostname. + * @param {string} opts.publicKeyFilePath - Path to the PGP public key file for encryption. + * @param {string} opts.clientCertP12FilePath - Path to the PKCS#12 client certificate file. + * @param {string} opts.clientCertP12Password - Password for the PKCS#12 client certificate password. + * @param {string} opts.serverTrustCertPath - Path to the server trust certificate file (optional). + * @param {boolean} [opts.verify_ssl=true] - Whether to reject unauthorized SSL certificates (optional). + * @param {function(Error, any):void} callback - Callback function with (error, result). + */ + uploadBatchAPIWithP12(opts, callback) { + const { + inputFilePath, + environmentHostname, + publicKeyFilePath, + clientCertP12FilePath, + clientCertP12Password, + serverTrustCertPath, + verify_ssl = true + } = opts; + try { + if (verify_ssl === false) { + this.logger.warn('verify_ssl is set to false. SSL verification is DISABLED. This setting is NOT SAFE for production and should NOT be used in production environments!'); + } + this.logger.info('Starting batch upload with p12/pfx for given file'); + const endpoint = '/pts/v1/transaction-batch-upload'; + const endpointUrl = BatchUploadUtility.getEndpointUrl(environmentHostname, endpoint); + BatchUploadUtility.validateBatchApiP12Inputs( + inputFilePath, environmentHostname, publicKeyFilePath, clientCertP12FilePath, serverTrustCertPath + ); + + PgpEncryptionUtility.handlePGPEncrypt(inputFilePath, publicKeyFilePath) + .then(encryptedBuffer => { + let uploadFileName = 'file.pgp'; + if (inputFilePath && inputFilePath.trim()) { + const base = path.basename(inputFilePath, path.extname(inputFilePath)); + uploadFileName = base + '.pgp'; + } + const clientCertP12 = fs.readFileSync(clientCertP12FilePath); + const serverTrustCert = serverTrustCertPath ? fs.readFileSync(serverTrustCertPath) : undefined; + return MutualAuthUploadUtility.handleUploadOperationUsingP12orPfx( + encryptedBuffer, + endpointUrl, + uploadFileName, + clientCertP12, + clientCertP12Password, + serverTrustCert, + verify_ssl + ); + }) + .then(result => { + callback(null, result); + this.logger.info(Constants.END_TRANSACTION); + }) + .catch(error => { + const errorMsg = error?.message || error?.error?.message || error.stack; + this.logger.error(errorMsg); + callback(error, (error && error.response) ? error.response : undefined); + this.logger.info(Constants.END_TRANSACTION); + }); + } catch (e) { + this.logger.error('Exception in Batch Upload API', e); + callback(e); + this.logger.info(Constants.END_TRANSACTION); + } + } + + /** + * Uploads a batch file to CyberSource using a client private key and certificate for mutual TLS authentication. + * The file is PGP-encrypted before upload. + * + * @param {Object} opts - Options for the upload. + * @param {string} opts.inputFilePath - Path to the input file to be uploaded. + * @param {string} opts.environmentHostname - CyberSource environment hostname. + * @param {string} opts.publicKeyFilePath - Path to the PGP public key file for encryption. + * @param {string} opts.clientPrivateKeyFilePath - Path to the client private key file. + * @param {string} opts.clientCertFilePath - Path to the client certificate file. + * @param {string} opts.serverTrustCertPath - Path to the server trust certificate file (optional). + * @param {string} [opts.clientKeyPassword] - Password for the client private key (if encrypted). + * @param {boolean} [opts.verify_ssl=true] - Whether to reject unauthorized SSL certificates (optional). + * @param {function(Error, any):void} callback - Callback function with (error, result). + */ + + uploadBatchAPIWithKeys(opts, callback) { + const { + inputFilePath, + environmentHostname, + publicKeyFilePath, + clientPrivateKeyFilePath, + clientCertFilePath, + serverTrustCertPath, + clientKeyPassword, + verify_ssl = true + } = opts; + try { + if (verify_ssl === false) { + this.logger.warn('verify_ssl is set to false. SSL verification is DISABLED. This setting is NOT SAFE for production and should NOT be used in production environments!'); + } + this.logger.info('Starting batch upload with client private key and certs for given file'); + const endpoint = '/pts/v1/transaction-batch-upload'; + const endpointUrl = BatchUploadUtility.getEndpointUrl(environmentHostname, endpoint); + BatchUploadUtility.validateBatchApiKeysInputs( + inputFilePath, environmentHostname, publicKeyFilePath, clientPrivateKeyFilePath, clientCertFilePath, serverTrustCertPath + ); + + PgpEncryptionUtility.handlePGPEncrypt(inputFilePath, publicKeyFilePath) + .then(encryptedBuffer => { + let uploadFileName = 'file.pgp'; + if (inputFilePath && inputFilePath.trim()) { + const base = path.basename(inputFilePath, path.extname(inputFilePath)); + uploadFileName = base + '.pgp'; + } + const clientPrivateKey = fs.readFileSync(clientPrivateKeyFilePath); + const clientCert = fs.readFileSync(clientCertFilePath); + const serverTrustCert = serverTrustCertPath ? fs.readFileSync(serverTrustCertPath) : undefined; + return MutualAuthUploadUtility.handleUploadOperationUsingPrivateKeyAndCerts( + encryptedBuffer, + endpointUrl, + uploadFileName, + clientPrivateKey, + clientCert, + serverTrustCert, + clientKeyPassword, + verify_ssl + ); + }) + .then(result => { + callback(null, result); + this.logger.info(Constants.END_TRANSACTION); + }) + .catch(error => { + const errorMsg = error?.message || error?.error?.message || error.stack; + this.logger.error(errorMsg); + callback(error, (error && error.response) ? error.response : undefined); + this.logger.info(Constants.END_TRANSACTION); + }); + } catch (e) { + this.logger.error('Exception in Batch Upload API', e); + callback(e); + this.logger.info(Constants.END_TRANSACTION); + } + } +} + +module.exports = BatchUploadWithMTLSApi; \ No newline at end of file diff --git a/src/authentication/logging/Logger.js b/src/authentication/logging/Logger.js index 0b7679b9..d0d7096e 100644 --- a/src/authentication/logging/Logger.js +++ b/src/authentication/logging/Logger.js @@ -14,15 +14,19 @@ const unmaskedLoggingFormat = printf(({ level, message, label, timestamp }) => { }); exports.getLogger = function (merchantConfig, loggerCategory = 'UnknownCategoryLogger') { + return exports.getLoggerFromLogConfig(merchantConfig.getLogConfiguration(), loggerCategory); +} + +exports.getLoggerFromLogConfig = function (logConfig, loggerCategory = 'UnknownCategoryLogger') { - if(merchantConfig.getLogConfiguration().isExternalLoggerSet() && merchantConfig.getLogConfiguration().getExternalLogger() - && merchantConfig.getLogConfiguration().getExternalLogger().getLogger() - && merchantConfig.getLogConfiguration().getExternalLogger() instanceof ExternalLoggerWrapper){ - let logger = merchantConfig.getLogConfiguration().getExternalLogger().getLogger(); + if (logConfig.isExternalLoggerSet() && logConfig.getExternalLogger() + && logConfig.getExternalLogger().getLogger() + && logConfig.getExternalLogger() instanceof ExternalLoggerWrapper) { + let logger = logConfig.getExternalLogger().getLogger(); return logger; } - var enableLog = merchantConfig.getLogConfiguration().isLogEnabled(); - var enableMasking = merchantConfig.getLogConfiguration().isMaskingEnabled(); + var enableLog = logConfig.isLogEnabled(); + var enableMasking = logConfig.isMaskingEnabled(); var loggerCategoryRandomiser = Math.floor(Math.random() * (1000000000 - 100 + 1)) + 100; loggerCategory = loggerCategory + loggerCategoryRandomiser; @@ -30,16 +34,16 @@ exports.getLogger = function (merchantConfig, loggerCategory = 'UnknownCategoryL var newLogger; if (enableLog) { - var appTransports = createTransportFromConfig(merchantConfig); + var appTransports = createTransportFromConfig(logConfig); - var loggingLevel = merchantConfig.getLogConfiguration().getLoggingLevel(); + var loggingLevel = logConfig.getLoggingLevel(); newLogger = winston.loggers.get(loggerCategory, { level: loggingLevel, format: combine( - label({ label: loggerCategory }), - timestamp(), - enableMasking ? maskedLoggingFormat : unmaskedLoggingFormat + label({ label: loggerCategory }), + timestamp(), + enableMasking ? maskedLoggingFormat : unmaskedLoggingFormat ), transports: appTransports }); @@ -47,9 +51,9 @@ exports.getLogger = function (merchantConfig, loggerCategory = 'UnknownCategoryL newLogger = winston.loggers.get(loggerCategory, { level: loggingLevel, format: combine( - label({ label: loggerCategory }), - timestamp(), - enableMasking ? maskedLoggingFormat : unmaskedLoggingFormat + label({ label: loggerCategory }), + timestamp(), + enableMasking ? maskedLoggingFormat : unmaskedLoggingFormat ), transports: [new winston.transports.Console({ silent: !enableLog @@ -60,14 +64,15 @@ exports.getLogger = function (merchantConfig, loggerCategory = 'UnknownCategoryL return newLogger; } -function createTransportFromConfig(mConfig) { + +function createTransportFromConfig(logConfig) { var transports = []; - var enableLog = mConfig.getLogConfiguration().isLogEnabled(); - var loggingLevel = mConfig.getLogConfiguration().getLoggingLevel(); - var maxLogFiles = mConfig.getLogConfiguration().getMaxLogFiles(); - var logFileName = mConfig.getLogConfiguration().getLogFileName(); - var logDirectory = mConfig.getLogConfiguration().getLogDirectory(); + var enableLog = logConfig.isLogEnabled(); + var loggingLevel = logConfig.getLoggingLevel(); + var maxLogFiles = logConfig.getMaxLogFiles(); + var logFileName = logConfig.getLogFileName(); + var logDirectory = logConfig.getLogDirectory(); transports.push(new winston.transports.DailyRotateFile({ level: loggingLevel, diff --git a/src/utilities/PGP/BatchUpload/BatchUploadUtility.js b/src/utilities/PGP/BatchUpload/BatchUploadUtility.js new file mode 100644 index 00000000..82701024 --- /dev/null +++ b/src/utilities/PGP/BatchUpload/BatchUploadUtility.js @@ -0,0 +1,118 @@ +const fs = require('fs'); +const path = require('path'); + +const MAX_FILE_SIZE_BYTES = 75 * 1024 * 1024; // 75MB + +class BatchUploadUtility { + /** + * Constructs the full endpoint URL for the given environment hostname and endpoint path. + * @param {string} environmentHostname - The environment hostname (with or without protocol prefix). + * @param {string} endpoint - The endpoint path to append. + * @returns {string} The full endpoint URL. + */ + static getEndpointUrl(environmentHostname, endpoint) { + const URL_PREFIX = 'https://'; + let baseUrl; + if (environmentHostname.trim().toLowerCase().startsWith(URL_PREFIX)) { + baseUrl = environmentHostname.trim(); + } else { + baseUrl = URL_PREFIX + environmentHostname.trim(); + } + return baseUrl + endpoint; + } + + /** + * Validates the input parameters for batch API using P12 client certificate. + * @param {string} inputFile - Path to the input CSV file for batch upload. + * @param {string} environmentHostname + * @param {string} pgpEncryptionCertPath - Path to the PGP public key file (.asc). + * @param {string} clientCertP12FilePath - Path to the client P12 certificate file. + * @param {string} serverTrustCertPath - Path to the server trust certificate file (PEM, optional). + */ + static validateBatchApiP12Inputs(inputFile, environmentHostname, pgpEncryptionCertPath, clientCertP12FilePath, serverTrustCertPath) { + this.validateInputFile(inputFile); + if (!environmentHostname || !environmentHostname.trim()) { + throw new Error('Environment Host Name for Batch Upload API cannot be null or empty.'); + } + this.validatePathAndFile(pgpEncryptionCertPath, 'PGP Encryption Cert Path'); + this.validatePathAndFile(clientCertP12FilePath, 'Client Cert P12 File Path'); + // serverTrustCertPath is optional, but if provided, validate + if (serverTrustCertPath && serverTrustCertPath.trim()) { + this.validatePathAndFile(serverTrustCertPath, 'Server Trust Cert Path'); + } + } + + /** + * Validates the input parameters for batch API using direct key and certificate file paths. + * @param {string} inputFile - Path to the input CSV file for batch upload. + * @param {string} environmentHostname + * @param {string} pgpPublicKeyPath - Path to the PGP public key file (.asc). + * @param {string} clientPrivateKeyPath - Path to the client private key file (PEM). + * @param {string} clientCertPath - Path to the client certificate file (PEM). + * @param {string} serverTrustCertPath - Path to the server trust certificate file (PEM, optional). + */ + static validateBatchApiKeysInputs(inputFile, environmentHostname, pgpPublicKeyPath, clientPrivateKeyPath, clientCertPath, serverTrustCertPath) { + this.validateInputFile(inputFile); + if (!environmentHostname || !environmentHostname.trim()) { + throw new Error('Environment Host Name for Batch Upload API cannot be null or empty.'); + } + this.validatePathAndFile(pgpPublicKeyPath, 'PGP Public Key Path'); + this.validatePathAndFile(clientPrivateKeyPath, 'Client Private Key Path'); + this.validatePathAndFile(clientCertPath, 'Client Certificate Path'); + // serverTrustCertPath is optional, but if provided, validate + if (serverTrustCertPath && serverTrustCertPath.trim()) { + this.validatePathAndFile(serverTrustCertPath, 'Server Trust Certificate Path'); + } + } + + /** + * Validates the input file for batch upload. + * Checks for existence, file type (CSV), and maximum file size (75MB). + * @param {string} inputFile - Path to the input file to validate. + */ + static validateInputFile(inputFile) { + if (!inputFile || !fs.existsSync(inputFile) || !fs.statSync(inputFile).isFile()) { + throw new Error(`Input file is invalid or does not exist: ${inputFile}`); + } + // Only CSV files are allowed for batch API + if (!inputFile.toLowerCase().endsWith('.csv')) { + throw new Error(`Only CSV file type is allowed: ${path.basename(inputFile)}`); + } + // Max file size allowed is 75MB + const fileSize = fs.statSync(inputFile).size; + if (fileSize > MAX_FILE_SIZE_BYTES) { + throw new Error(`Input file size exceeds the maximum allowed size of 75MB: ${fileSize}`); + } + } + + /** + * Validates that the given file path exists and is not empty. + * @param {string} filePath - The file path to validate. + * @param {string} pathType - A description of the path type (e.g., "Input file"). + */ + static validatePathAndFile(filePath, pathType) { + if (!filePath || !filePath.trim()) { + throw new Error(`${pathType} path cannot be null or empty`); + } + + // Normalize Windows-style paths that start with a slash before the drive letter + let normalizedPath = filePath.trim(); + if (path.sep === '\\' && normalizedPath.match(/^\/[A-Za-z]:.*/)) { + normalizedPath = normalizedPath.substring(1); + } + + if (!fs.existsSync(normalizedPath)) { + throw new Error(`${pathType} does not exist: ${normalizedPath}`); + } + if (!fs.statSync(normalizedPath).isFile()) { + throw new Error(`${pathType} does not have valid file: ${normalizedPath}`); + } + try { + fs.accessSync(normalizedPath, fs.constants.R_OK); + } catch (err) { + throw new Error(`${pathType} is not readable: ${normalizedPath}`); + } + } +} + +module.exports = BatchUploadUtility; \ No newline at end of file diff --git a/src/utilities/PGP/BatchUpload/MutualAuthUploadUtility.js b/src/utilities/PGP/BatchUpload/MutualAuthUploadUtility.js new file mode 100644 index 00000000..4aaa829f --- /dev/null +++ b/src/utilities/PGP/BatchUpload/MutualAuthUploadUtility.js @@ -0,0 +1,162 @@ +const axios = require('axios'); +const fs = require('fs'); +const https = require('https'); +const tls = require('tls'); +const FormData = require('form-data'); +const { v4: uuidv4 } = require('uuid'); + +/** + * Uploads an encrypted PGP file using mTLS with PKCS#12 (.p12/.pfx) client certificate. + * @param {Buffer} encryptedPgpBytes - The encrypted PGP file content as Buffer. + * @param {string} fileName - The name of the file to be uploaded. + * @param {Buffer} clientCertP12 - The PKCS#12 client certificate as Buffer. + * @param {string} clientCertP12Password - Password for the PKCS#12 client certificate. + * @param {Buffer} serverTrustCert - The server trust certificate as Buffer. + * @returns {Promise} + */ +function handleUploadOperationUsingP12orPfx( + encryptedPgpBytes, + endpointUrl, + fileName, + clientCertP12, + clientCertP12Password, + serverTrustCert, + verify_ssl +) { + const form = new FormData(); + form.append('file', encryptedPgpBytes, { filename: fileName }); + + const defaultCAs = tls.rootCertificates.slice(); + //Assuming serverTrustCert is a PEM encoded certificate + if (serverTrustCert && serverTrustCert.length > 0) { + defaultCAs.push(serverTrustCert.toString()); + } + + const correlationId = uuidv4(); + + const cleanServername = new URL(endpointUrl).hostname; + + const httpsAgent = new https.Agent({ + pfx: clientCertP12, + passphrase: clientCertP12Password, + ca: defaultCAs, + rejectUnauthorized: verify_ssl, + servername: cleanServername + }); + + return axios.post(endpointUrl, form, { + httpsAgent, + headers: { + ...form.getHeaders(), + 'v-c-correlation-id': correlationId + } + }).then(response => { + if (response.status >= 200 && response.status < 300) { + return normalizeResponse(response); + } throw { + response + }; + }).catch(error => { + return Promise.reject({ + error: normalizeErrorResponse(error), + response: error.response + }); + }); +} + +/** + * Uploads an encrypted PGP file using mTLS with client key/cert as PEM Buffers/strings. + * @param {Buffer} encryptedPgpBytes - The encrypted PGP file content as Buffer. + * @param {string} fileName - The name of the file to be uploaded. + * @param {Buffer|string} clientPrivateKey - The client's private key (Buffer). + * @param {Buffer|string} clientCert - The client's certificate (Buffer). + * @param {Buffer|string} serverTrustCert - The server's trust certificate (Buffer). + * @param {string} [clientKeyPassword] - Password for the private key, if encrypted. + * @returns {Promise} + */ +function handleUploadOperationUsingPrivateKeyAndCerts( + encryptedPgpBytes, + endpointUrl, + fileName, + clientPrivateKey, + clientCert, + serverTrustCert, + clientKeyPassword, + verify_ssl +) { + const form = new FormData(); + form.append('file', encryptedPgpBytes, { filename: fileName }); + + const correlationId = uuidv4(); + + const defaultCAs = tls.rootCertificates.slice(); + //Assuming serverTrustCert is a PEM encoded certificate + if (serverTrustCert && serverTrustCert.length > 0) { + defaultCAs.push(serverTrustCert.toString()); + } + + const cleanServername = new URL(endpointUrl).hostname; + + const httpsAgent = new https.Agent({ + key: clientPrivateKey, + cert: clientCert, + ca: defaultCAs, + passphrase: clientKeyPassword, + rejectUnauthorized: verify_ssl, + servername: cleanServername + }); + + return axios.post(endpointUrl, form, { + httpsAgent, + headers: { + ...form.getHeaders(), + 'v-c-correlation-id': correlationId + } + }).then(response => { + if (response.status >= 200 && response.status < 300) { + return normalizeResponse(response); + } throw { + response + }; + }).catch(function(error) { + return Promise.reject({ + error: normalizeErrorResponse(error), + response: error.response + }); + }); +} + +function normalizeResponse(response) { + return { + status: response.status, + statusText: response.statusText, + data: response.data, + header: response.headers, + message: "File uploaded successfully" + }; +} + +function normalizeErrorResponse(error) { + if (typeof error.response !== 'undefined') { + return { + status: error.response.status, + statusText: error.response.statusText, + data: error.response.data, + header: error.response.headers, + message: `File upload failed: ${error.message}` + }; + } else { + var tester = {}; + tester.errno = error.errno; + tester.code = error.code; + tester.syscall = error.syscall; + tester.address = error.address; + tester.port = error.port; + tester.message = error.message ? error.message : 'An unknown error occurred'; + return tester; + } +} +module.exports = { + handleUploadOperationUsingP12orPfx, + handleUploadOperationUsingPrivateKeyAndCerts +}; \ No newline at end of file diff --git a/src/utilities/PGP/BatchUpload/PgpEncryptionUtility.js b/src/utilities/PGP/BatchUpload/PgpEncryptionUtility.js new file mode 100644 index 00000000..b8ff335b --- /dev/null +++ b/src/utilities/PGP/BatchUpload/PgpEncryptionUtility.js @@ -0,0 +1,36 @@ +const fs = require('fs'); +const openpgp = require('openpgp'); + +/** + * Encrypts a file using a PGP public key (.asc). + * @param {string} inputFilePath - Path to the file to encrypt. + * @param {string} publicKeyPath - Path to the public .asc key or armored key string. + * @returns {Promise} - The encrypted file as a Buffer. + */ +function handlePGPEncrypt(inputFilePath, publicKeyPath) { + return new Promise((resolve, reject) => { + let publicKeyArmored, fileData; + try { + publicKeyArmored = fs.readFileSync(publicKeyPath, 'utf8'); + fileData = fs.readFileSync(inputFilePath); + } catch (err) { + return reject(err); + } + openpgp.readKey({ armoredKey: publicKeyArmored }) + .then(publicKey => { + return openpgp.createMessage({ binary: fileData }) + .then(message => { + return openpgp.encrypt({ + message, + encryptionKeys: publicKey, + config: { preferredCompressionAlgorithm: openpgp.enums.compression.zip }, + format: 'binary' + }); + }); + }) + .then(encrypted => resolve(Buffer.from(encrypted))) + .catch(reject); + }); +} + +module.exports = { handlePGPEncrypt }; \ No newline at end of file