From 2093cda9a3526a5af40c2aa6e55ff13b5a55fb77 Mon Sep 17 00:00:00 2001 From: Manish Prajapati <129747412+manishprajapati52@users.noreply.github.com> Date: Wed, 26 Jun 2024 18:45:47 +0530 Subject: [PATCH 1/2] Add strict ssl and cafile flag support (#309) * VPN firewall issue * Provide option to pass custom certificate --------- Co-authored-by: vivek-gofynd --- README.md | 90 +++++++++++++++++++++++++- package-lock.json | 4 +- package.json | 2 +- src/commands/config/config-builder.ts | 80 +++++++++++++++++++++++ src/commands/config/index.ts | 6 ++ src/commands/index.ts | 1 + src/fdk.ts | 38 ++++++++++- src/helper/serve.utils.ts | 28 ++++++-- src/lib/Auth.ts | 2 + src/lib/Config.ts | 3 + src/lib/api/ApiClient.ts | 1 + src/lib/api/helper/interceptors.ts | 9 +++ src/lib/api/services/upload.service.ts | 1 + 13 files changed, 254 insertions(+), 11 deletions(-) create mode 100644 src/commands/config/config-builder.ts create mode 100644 src/commands/config/index.ts diff --git a/README.md b/README.md index e0a90440..751d0bdc 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,14 @@ ___ | [preview-url](#extension-preview-url) | Create a ngrok tunnel and provide a link to tryout extension on development company | [launch-url](#extension-launch-url) | Get/set extension's lanuch url | +### Config Commands + +| Command Type | Description | +|--------------|--------------------------------------| +| [set](#config-set-commands) | Set configuration values. | +| [get](#config-get-commands) | Retrieve current configuration values.| +| [delete](#config-delete-commands) (alias: `rm`) | Delete configuration values. | +
@@ -104,7 +112,6 @@ fdk login --verbose
## Commands Reference -___ ### Environment Commands Before you start using FDK CLI you will have to set an environment @@ -472,6 +479,87 @@ fdk partner connect [options] fdk partner connect ``` ___ +### Config Commands +
+ +
+ +#### Set Commands +The `set` commands allow you to configure the `cafile` and `strict-ssl` settings for the tool. This is useful for ensuring that the tool uses the correct SSL certificates and validation settings according to your requirements. + +| Command | Description | +|-------------------------------------------|----------------------------------------------| +| `set cafile ` | Sets the CA file to the specified file path. | +| `set strict-ssl ` | Enables or disables strict SSL validation. | + +#### **Example** +```sh +fdk config set cafile /etc/ssl/certs/ca-certificates.pem +``` +```sh +fdk config set strict-ssl false +``` + +#### Notes + +> - Ensure that the file path provided for the CA file is valid and accessible. +> - The strict SSL setting should be either `true` or `false`. + +#### Environment Variables + +> Developers can configure settings using environment variables.

`FDK_EXTRA_CA_CERTS`: Set this variable to specify the CA file path (`cafile`). +

`FDK_SSL_NO_VERIFY`: Set this variable to `true` to disable strict SSL validation (`strict-ssl=false`).
+ +#### **Example** + +```sh +FDK_EXTRA_CA_CERTS=/path/to/your/cafile fdk login +``` +```sh +FDK_SSL_NO_VERIFY=true fdk login +``` + +
+ +#### Get Commands +The `get` commands allow you to view the current configuration values for `cafile` and `strict-ssl`. This is useful for verifying what values are currently set and ensuring that your configuration is correct. + +| Command | Description | +|-------------------------------|----------------------------------------------| +| `get cafile` | Retrieves the current CA file path. | +| `get strict-ssl` | Retrieves the current strict SSL setting. | + +#### **Example** +```sh +fdk config get cafile +``` +```sh +fdk config get strict-ssl +``` + +
+ +#### Delete Commands +The `delete` commands allow you to remove the current configuration for `cafile` and `strict-ssl`. This can be useful for resetting configurations or removing settings that are no longer needed. + +| Command | Description | +|------------------------------- |----------------------------------------------| +| `delete cafile` | Deletes the current CA file configuration. | +| `delete strict-ssl` | Deletes the current strict SSL configuration.| +| `rm cafile` | Alias for `delete`: Deletes the current CA file configuration. | + + +#### **Example** +```sh +fdk config delete cafile +``` +```sh +fdk config delete strict-ssl +``` +```sh +fdk config rm cafile +``` +___
diff --git a/package-lock.json b/package-lock.json index ff068e50..3728663d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@gofynd/fdk-cli", - "version": "5.1.0", + "version": "5.1.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@gofynd/fdk-cli", - "version": "5.1.0", + "version": "5.1.1", "license": "MIT", "dependencies": { "@babel/core": "7.14.3", diff --git a/package.json b/package.json index df6fd9e1..529d8196 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@gofynd/fdk-cli", - "version": "5.1.0", + "version": "5.1.1", "main": "index.js", "license": "MIT", "bin": { diff --git a/src/commands/config/config-builder.ts b/src/commands/config/config-builder.ts new file mode 100644 index 00000000..def9b853 --- /dev/null +++ b/src/commands/config/config-builder.ts @@ -0,0 +1,80 @@ +import { Command } from 'commander'; +import Configstore, { CONFIG_KEYS } from '../../lib/Config'; +import fs from 'fs-extra'; +import chalk from 'chalk'; + +export default function extensionCommandBuilder() { + const configCommander = new Command('config').description( + 'Config Commands', + ); + const setCommander = new Command('set').description( + 'set config items', + ); + + setCommander + .command('cafile ') + .description('To set CA file') + .action((caFilePath: string) => { + if (fs.existsSync(caFilePath)) { + Configstore.set(CONFIG_KEYS.CA_FILE, caFilePath); + } else { + console.log(chalk.red("Provided file path does not exist.")); + } + }) + + setCommander + .command('strict-ssl ') + .description('To set CA file') + .action((value: string) => { + const ACCEPTED_VALUES = ['false', 'true'] + if (ACCEPTED_VALUES.includes(value)) { + Configstore.set(CONFIG_KEYS.STRICT_SSL, value); + } else { + console.log(chalk.red("Entered value is not valid.")); + } + }) + + configCommander.addCommand(setCommander); + + const getCommander = new Command('get').description( + 'set config items', + ); + + getCommander + .command('cafile') + .description('To set CA file') + .action(() => { + console.log(Configstore.get(CONFIG_KEYS.CA_FILE) || ""); + }) + + getCommander + .command('strict-ssl') + .description('To set strict-ssl') + .action(() => { + console.log(Configstore.get(CONFIG_KEYS.STRICT_SSL) || ""); + }) + + configCommander.addCommand(getCommander); + + const deleteCommander = new Command('delete').alias('rm').description( + 'delete config items', + ); + + deleteCommander + .command('cafile') + .description('To delete CA file') + .action(() => { + Configstore.delete(CONFIG_KEYS.CA_FILE) + }) + + deleteCommander + .command('strict-ssl') + .description('To reset strict-ssl') + .action(() => { + Configstore.delete(CONFIG_KEYS.STRICT_SSL) + }) + + configCommander.addCommand(deleteCommander); + + return configCommander; +} diff --git a/src/commands/config/index.ts b/src/commands/config/index.ts new file mode 100644 index 00000000..810e359a --- /dev/null +++ b/src/commands/config/index.ts @@ -0,0 +1,6 @@ +import { Command } from 'commander'; + +import configCommandBuilder from './config-builder'; +export default function env(program: Command) { + program.addCommand(configCommandBuilder()); +} diff --git a/src/commands/index.ts b/src/commands/index.ts index f2a0b94c..ad5cf261 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -7,6 +7,7 @@ const COMMANDS = [ require('./populate'), require('./extension'), require('./partner'), + require('./config'), ]; export function registerCommands(program: CommanderStatic) { diff --git a/src/fdk.ts b/src/fdk.ts index 127d5e5d..5a0a73f1 100644 --- a/src/fdk.ts +++ b/src/fdk.ts @@ -76,8 +76,44 @@ Command.prototype.asyncAction = async function (asyncFn: Action) { } else { process.env.DEBUG = 'false'; } - initializeLogger(); + + // check in config if user have set certificate + const CA_FILE = configStore.get(CONFIG_KEYS.CA_FILE) + // if user shared certificate while executing the command + const sharedInlineCert = process.env.FDK_EXTRA_CA_CERTS; + + // if shared inline then it should be exist + if(sharedInlineCert && !fs.existsSync(sharedInlineCert)){ + throw new CommandError("Provided file path does not exist."); + } + // inline CA will get priority + if (!sharedInlineCert && CA_FILE) { + process.env.FDK_EXTRA_CA_CERTS = CA_FILE; + } + + if(process.env.FDK_EXTRA_CA_CERTS){ + Logger.info(`Using CA file from ${process.env.FDK_EXTRA_CA_CERTS}`) + } + + const disableSSL = () => { + process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; + process.env.FDK_SSL_NO_VERIFY = 'true'; + } + + const sharedInlineNoSSL = process.env.FDK_SSL_NO_VERIFY; + const STRICT_SSL = configStore.get(CONFIG_KEYS.STRICT_SSL); + if(sharedInlineNoSSL == 'true'){ + disableSSL(); + } + if(!sharedInlineNoSSL && STRICT_SSL == 'false'){ + disableSSL(); + } + + if(process.env.FDK_SSL_NO_VERIFY == 'true'){ + Logger.warn(`Bypassing SSL verification`) + } + const latest = await checkCliVersionAsync(); const isCurrentLessThanLatest = semver.lt( packageJSON.version, diff --git a/src/helper/serve.utils.ts b/src/helper/serve.utils.ts index 1e45f9ad..94c80541 100644 --- a/src/helper/serve.utils.ts +++ b/src/helper/serve.utils.ts @@ -23,6 +23,7 @@ import webpackHotMiddleware from 'webpack-hot-middleware'; import webpack from 'webpack'; import createBaseWebpackConfig from '../helper/theme.react.config'; import Debug from '../lib/Debug'; +import https from 'https'; const packageJSON = require('../../package.json'); const BUILD_FOLDER = './.fdk/dist'; @@ -56,12 +57,27 @@ export function getPort(port) { function applyProxy(app: any) { const currentContext = getActiveContext(); const currentDomain = `https://${currentContext.domain}`; + let httpsAgent; + + if(process.env.FDK_EXTRA_CA_CERTS){ + // Load the VPN's CA certificate + const ca = fs.readFileSync(process.env.FDK_EXTRA_CA_CERTS); + // Create an HTTPS agent with the CA certificate + httpsAgent = { ca } + } + if(process.env.FDK_SSL_NO_VERIFY == 'true'){ + httpsAgent = { rejectUnauthorized: false } + } + if(httpsAgent){ + httpsAgent = new https.Agent(httpsAgent); + } const options = { target: currentDomain, // target host changeOrigin: true, // needed for virtual hosted sites cookieDomainRewrite: '127.0.0.1', // rewrite cookies to localhost onProxyReq: fixRequestBody, onError: (error) => Logger.error(error), + agent: httpsAgent }; // proxy to solve CORS issue @@ -137,10 +153,10 @@ async function requestToOriginalSource(req, res, domain, themeId) { return res.send(publicCache[url].body); } catch (error) { // If there's an error, pass it to the client - if (error.response) { + if (error?.response) { // If there is a response from the server - res.status(error.response.status).send(error.response.data); - } else if (error.request) { + res.status(error?.response?.status).send(error?.response?.data); + } else if (error?.request) { // If the request was made but no response was received res.status(500).send('No response from server'); } else { @@ -215,7 +231,7 @@ export async function startServer({ domain, host, isSSR, port }) { data: { theme_url: themeUrl, domain: getFullLocalUrl(port), - }, + } }); let $ = cheerio.load(html); @@ -269,9 +285,9 @@ export async function startServer({ domain, host, isSSR, port }) { }); res.send($.html({ decodeEntities: false })); } catch (e) { - if (e.response && e.response.status == 504) { + if (e?.response && e?.response?.status == 504) { res.redirect(req.originalUrl); - } else if (e.response && e.response.status == 500) { + } else if (e?.response && e?.response?.status == 500) { try { Logger.error(e.response.data); let errorString = e.response.data diff --git a/src/lib/Auth.ts b/src/lib/Auth.ts index fba31ac6..1ebd23b0 100644 --- a/src/lib/Auth.ts +++ b/src/lib/Auth.ts @@ -138,8 +138,10 @@ export default class Auth { const currentEnv = ConfigStore.get( CONFIG_KEYS.CURRENT_ENV_VALUE, ); + const extras = ConfigStore.get(CONFIG_KEYS.EXTRAS); ConfigStore.clear(); ConfigStore.set(CONFIG_KEYS.CURRENT_ENV_VALUE, currentEnv); + ConfigStore.set(CONFIG_KEYS.EXTRAS, extras); Logger.info(`User logged out successfully`); } }); diff --git a/src/lib/Config.ts b/src/lib/Config.ts index c5a5341b..8005796a 100644 --- a/src/lib/Config.ts +++ b/src/lib/Config.ts @@ -12,6 +12,9 @@ export const CONFIG_KEYS = { COMPANY_ID: 'current_env.company_id', AUTH_TOKEN: 'current_env.auth_token', ORGANIZATION: 'current_env.organization', + EXTRAS: 'extras', + STRICT_SSL: 'extras.strict_ssl', + CA_FILE: 'extras.ca_file', }; // global config store - The config is stored in a JSON file located in $XDG_CONFIG_HOME or ~/.config diff --git a/src/lib/api/ApiClient.ts b/src/lib/api/ApiClient.ts index f6e72585..c2248b6a 100644 --- a/src/lib/api/ApiClient.ts +++ b/src/lib/api/ApiClient.ts @@ -19,6 +19,7 @@ import { import Curl from '../../helper/curl'; import Logger from '../Logger'; import { MAX_RETRY } from '../../helper/constants'; +import https from 'https' axios.defaults.withCredentials = true; axios.defaults.timeout = 60000; // 1 minute diff --git a/src/lib/api/helper/interceptors.ts b/src/lib/api/helper/interceptors.ts index c0eda289..95d86cd9 100644 --- a/src/lib/api/helper/interceptors.ts +++ b/src/lib/api/helper/interceptors.ts @@ -7,6 +7,8 @@ import ConfigStore, { CONFIG_KEYS } from '../../Config'; import { MAX_RETRY } from '../../../helper/constants'; import { COMMON_LOG_MESSAGES } from '../../../lib/Logger'; import { transformRequestOptions } from '../../../helper/utils'; +import fs from 'fs-extra'; +import https from 'https' function getTransformer(config) { const { transformRequest } = config; @@ -87,6 +89,13 @@ function interceptorFn(options) { config.headers['x-fp-date'] = signature['x-fp-date']; config.headers['x-fp-signature'] = signature['x-fp-signature']; } + if(process.env.FDK_EXTRA_CA_CERTS){ + // Load the VPN's CA certificate + const ca = fs.readFileSync(process.env.FDK_EXTRA_CA_CERTS); + // Create an HTTPS agent with the CA certificate + const httpsAgent = new https.Agent({ ca }); + config.httpsAgent = httpsAgent; + } return config; } catch (error) { throw error; diff --git a/src/lib/api/services/upload.service.ts b/src/lib/api/services/upload.service.ts index 01838100..9f0ba2d3 100644 --- a/src/lib/api/services/upload.service.ts +++ b/src/lib/api/services/upload.service.ts @@ -6,6 +6,7 @@ import fs from 'fs-extra'; import path from 'path'; import mime from 'mime'; import Spinner from '../../../helper/spinner'; + export default { startUpload: async (data, namespace) => { try { From 7a1116526f76265fc4a2e51a91022184263c3c3b Mon Sep 17 00:00:00 2001 From: Bhargav Prajapati <117252424+bhargavprajapatiFynd@users.noreply.github.com> Date: Thu, 4 Jul 2024 16:10:49 +0530 Subject: [PATCH 2/2] Extension init base_url bugfix (#318) * ID: FPCO-35348; Extension init bugfix * 5.1.2 --- package-lock.json | 4 ++-- package.json | 2 +- src/lib/Extension.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3728663d..2fe5391c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@gofynd/fdk-cli", - "version": "5.1.1", + "version": "5.1.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@gofynd/fdk-cli", - "version": "5.1.1", + "version": "5.1.2", "license": "MIT", "dependencies": { "@babel/core": "7.14.3", diff --git a/package.json b/package.json index 529d8196..dcb6105c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@gofynd/fdk-cli", - "version": "5.1.1", + "version": "5.1.2", "main": "index.js", "license": "MIT", "bin": { diff --git a/src/lib/Extension.ts b/src/lib/Extension.ts index 1e14a141..debfa6d8 100644 --- a/src/lib/Extension.ts +++ b/src/lib/Extension.ts @@ -191,7 +191,7 @@ export default class Extension { await ExtensionService.registerExtensionPartners(data); answers.extension_api_key = extension_data.client_id; answers.extension_api_secret = extension_data.secret; - answers.base_url = extension_data.launch_url; + answers.base_url = extension_data.base_url; spinner.succeed(); } catch (error) { spinner.fail();