Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

Commit

Permalink
Restrict general help content in REPL context (#5885)
Browse files Browse the repository at this point in the history
Restrict general help in REPL context

General help can be requested in 2 contexts, the command line, and a REPL, both having a different set of valid truffle commands. This commit 1) moves the source of truth for valid, excluded (in REPL) and valid REPL commands to a single module. 2) modifies the `displayGeneralHelp` function to be context aware and display the appropriate help. 3) Updates tests and webpack to use the new source of truth.

## packages/core/lib/commands/commands.js
- define the single source of truth for valid, excluded and console only
  truffle commands that is easy to maintain.

## packages/core/lib/command-utils.js
- update logic to use the single source of truth
- modify `displayGeneralHelp()` to accept a flag specifying whether it is run in a REPL. If in a REPL, the logic will show help for console-only truffle commands.

## packages/core/lib/commands/console/run.js 
- use command source of truth instead of calculating

## packages/core/lib/commands/develop/run.js
- use command source of truth instead of calculating

## packages/core/lib/console-child.js
- modify `displayGeneralHelp()` to accept an `isREPL` option, which is used to display help for REPL commands or command line commands.

## packages/core/lib/console.js
- refactor to use truffle command source of truth and modified error messages for using excluded and invalid commands in the REPL

## misc
- packages/core/test/commands.js
- packages/core/test/lib/console.js
- packages/truffle/webpack.config.js
  - refactor to use command source of truth.
  • Loading branch information
cds-amal committed Feb 16, 2023
1 parent 2f38379 commit 591d3ac
Show file tree
Hide file tree
Showing 10 changed files with 79 additions and 77 deletions.
19 changes: 15 additions & 4 deletions packages/core/lib/command-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ const { extractFlags } = require("./utils/utils"); // contains utility methods
const globalCommandOptions = require("./global-command-options");
const debugModule = require("debug");
const debug = debugModule("core:command:run");
const commands = require("./commands/commands");
const {
validTruffleCommands,
validTruffleConsoleCommands
} = require("./commands/commands");
const Web3 = require("web3");
const TruffleError = require("@truffle/error");

Expand Down Expand Up @@ -116,11 +119,11 @@ const getCommand = ({ inputStrings, options, noAliases }) => {
// for inferring the command.
if (firstInputString === "-v" || firstInputString === "--version") {
chosenCommand = "version";
} else if (commands.includes(firstInputString)) {
} else if (validTruffleCommands.includes(firstInputString)) {
chosenCommand = firstInputString;
} else if (noAliases !== true) {
let currentLength = 1;
const availableCommandNames = commands;
const availableCommandNames = validTruffleCommands;

// Loop through each letter of the input until we find a command
// that uniquely matches.
Expand Down Expand Up @@ -294,8 +297,16 @@ const runCommand = async function (command, options) {
return await command.run(options);
};

const displayGeneralHelp = () => {
/**
* Display general help for Truffle commands
* @param {Object} options - options object
* @param {Boolean} options.isREPL - whether or not the help is being displayed in a REPL
* @returns {void}
*/
const displayGeneralHelp = options => {
const yargs = require("yargs/yargs")();
const isREPL = options?.isREPL ?? false; //default to not displaying REPL commands
const commands = isREPL ? validTruffleConsoleCommands : validTruffleCommands;
commands.forEach(command => {
// Exclude "install" and "publish" commands from the generated help list
// because they have been deprecated/removed.
Expand Down
23 changes: 21 additions & 2 deletions packages/core/lib/commands/commands.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// The list of commands that Truffle supports
module.exports = [
const validTruffleCommands = [
"build",
"compile",
"config",
Expand All @@ -26,3 +25,23 @@ module.exports = [
"version",
"watch"
];

//List of truffle commands that are excluded from the console REPLS.
const excludedTruffleConsoleCommands = [
"console",
"dashboard",
"db",
"develop",
"init",
"watch"
];

const validTruffleConsoleCommands = validTruffleCommands.filter(
command => !excludedTruffleConsoleCommands.includes(command)
);

module.exports = {
excludedTruffleConsoleCommands,
validTruffleCommands,
validTruffleConsoleCommands
};
13 changes: 2 additions & 11 deletions packages/core/lib/commands/console/run.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
module.exports = async function (options) {
const OS = require("os");
const { Console, excludedCommands } = require("../../console");
const { Console } = require("../../console");
const { Environment } = require("@truffle/environment");
const TruffleError = require("@truffle/error");
const commands = require("../commands");
const loadConfig = require("../../loadConfig");

if (options.url && options.network) {
Expand All @@ -19,15 +18,7 @@ module.exports = async function (options) {
}

let config = loadConfig(options);

const allowedConsoleCommands = commands.filter(
cmd => !excludedCommands.has(cmd)
);

await Environment.detect(config);
const c = new Console(
allowedConsoleCommands,
config.with({ noAliases: true })
);
const c = new Console(config.with({ noAliases: true }));
return await c.start();
};
12 changes: 2 additions & 10 deletions packages/core/lib/commands/develop/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,11 @@ const {
} = require("../../configAdapter");

const runConsole = async (config, ganacheOptions) => {
const { Console, excludedCommands } = require("../../console");
const { Console } = require("../../console");
const { Environment } = require("@truffle/environment");

const commands = require("../commands");
const allowedConsoleCommands = commands.filter(
cmd => !excludedCommands.has(cmd)
);

await Environment.develop(config, ganacheOptions);
const c = new Console(
allowedConsoleCommands,
config.with({ noAliases: true })
);
const c = new Console(config.with({ noAliases: true }));
c.on("exit", () => process.exit());
return await c.start();
};
Expand Down
2 changes: 1 addition & 1 deletion packages/core/lib/console-child.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const inputArguments = parseQuotesAndEscapes(input[1], escapeCharacters); //note
// handle cases where input indicates the user wants to access Truffle's help
const { displayHelp, inputStrings } = handleHelpInput({ inputArguments });
if (displayHelp) {
displayGeneralHelp();
displayGeneralHelp({ isREPL: true });
process.exit();
}

Expand Down
46 changes: 24 additions & 22 deletions packages/core/lib/console.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,17 @@ const EventEmitter = require("events");
const { spawn } = require("child_process");
const Require = require("@truffle/require");
const debug = require("debug")("console");
const { getCommand, parseQuotesAndEscapes } = require("./command-utils");
const validTruffleCommands = require("./commands/commands");
const { parseQuotesAndEscapes } = require("./command-utils");
const {
excludedTruffleConsoleCommands,
validTruffleConsoleCommands
} = require("./commands/commands");

// Create an expression that returns a string when evaluated
// by the REPL
const makeIIFE = str => `(() => "${str}")()`;

const processInput = (input, allowedCommands) => {
const processInput = input => {
const words = input.trim().split(/\s+/);

// empty input
Expand All @@ -39,20 +42,30 @@ const processInput = (input, allowedCommands) => {
}

const normalizedCommand = cmd.toLowerCase();
if (validTruffleCommands.includes(normalizedCommand)) {
return allowedCommands.includes(normalizedCommand)
? words.slice(1).join(" ")
: makeIIFE(`ℹ️ : '${cmd}' is not allowed within Truffle REPL`);
const isExcludedInREPL =
excludedTruffleConsoleCommands.includes(normalizedCommand);

if (isExcludedInREPL) {
return makeIIFE(
`ℹ️ : '${words[0]} ${cmd}' is not allowed in Console environment.`
);
}
return makeIIFE(`ℹ️ : '${cmd}' is not a valid Truffle command`);

if (!validTruffleConsoleCommands.includes(normalizedCommand)) {
return makeIIFE(
`ℹ️ : '${words[0]} ${cmd}' is not a valid truffle command.`
);
}

return words.slice(1).join(" ");
}

// an expression
return input.trim();
};

class Console extends EventEmitter {
constructor(allowedCommands, options) {
constructor(options) {
super();
EventEmitter.call(this);

Expand All @@ -69,7 +82,6 @@ class Console extends EventEmitter {
"build_directory"
]);

this.allowedCommands = allowedCommands;
this.options = options;

this.repl = null;
Expand Down Expand Up @@ -398,15 +410,8 @@ class Console extends EventEmitter {
}

async interpret(input, context, filename, callback) {
const processedInput = processInput(input, this.allowedCommands);
if (
this.allowedCommands.includes(processedInput.split(/\s+/)[0]) &&
getCommand({
inputStrings: processedInput.split(/\s+/),
options: {},
noAliases: this.options.noAliases
}) !== null
) {
const processedInput = processInput(input);
if (validTruffleConsoleCommands.includes(processedInput.split(/\s+/)[0])) {
try {
parseQuotesAndEscapes(processedInput); //we're just doing this to see
//if it errors. unfortunately we need to throw out the result and recompute
Expand Down Expand Up @@ -526,9 +531,6 @@ class Console extends EventEmitter {
}
}

const excludedCommands = new Set(["console", "db", "init", "watch", "develop"]);

module.exports = {
excludedCommands,
Console
};
6 changes: 3 additions & 3 deletions packages/core/test/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const {
prepareOptions,
runCommand
} = require("../lib/command-utils");
const commandsArray = require("../lib/commands/commands");
const { validTruffleCommands } = require("../lib/commands/commands");
const allCommands = require("../lib/commands");
const { assert } = require("chai");

Expand All @@ -14,13 +14,13 @@ describe("commands", function () {
it("contains an array item for each command", function () {
assert(
Object.keys(allCommands).every(command =>
commandsArray.includes(command)
validTruffleCommands.includes(command)
)
);
});
it("contains a command for every array item", function () {
assert(
commandsArray.every(command =>
validTruffleCommands.every(command =>
Object.keys(allCommands).includes(command)
)
);
Expand Down
23 changes: 5 additions & 18 deletions packages/core/test/lib/console.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
const assert = require("chai").assert;
const path = require("path");
const { Console, excludedCommands } = require("../../lib/console");
const commands = require("../../lib/commands");
const { Console } = require("../../lib/console");
const sinon = require("sinon");
const Config = require("@truffle/config");
const Web3 = require("web3");
const { Resolver } = require("@truffle/resolver");
const config = new Config();

const allowedConsoleCommands = Object.keys(commands).filter(
cmd => !excludedCommands.has(cmd)
);
let truffleConsole, consoleOptions;

describe("Console", function () {
Expand Down Expand Up @@ -40,7 +36,7 @@ describe("Console", function () {
{ path: pathToMoreUserJs },
{ path: pathToUserJs, as: "namespace" }
];
truffleConsole = new Console(allowedConsoleCommands, consoleOptions);
truffleConsole = new Console(consoleOptions);
sinon
.stub(truffleConsole.interfaceAdapter, "getAccounts")
.returns(["0x0"]);
Expand Down Expand Up @@ -86,10 +82,7 @@ describe("Console", function () {
"test/sources/moreUserVariables.js"
);
otherConsoleOptions["require-none"] = true;
otherTruffleConsole = new Console(
allowedConsoleCommands,
otherConsoleOptions
);
otherTruffleConsole = new Console(otherConsoleOptions);
});

it("won't load any user-defined JS", async function () {
Expand Down Expand Up @@ -118,10 +111,7 @@ describe("Console", function () {
config.working_directory,
"test/sources/nameConflicts.js"
);
otherTruffleConsole = new Console(
allowedConsoleCommands,
otherConsoleOptions
);
otherTruffleConsole = new Console(otherConsoleOptions);
});

it("won't let users clobber Truffle variables", async function () {
Expand All @@ -147,10 +137,7 @@ describe("Console", function () {
provider: new Web3.providers.WebsocketProvider("ws://localhost:666"),
resolver: new Resolver(config)
});
otherTruffleConsole = new Console(
allowedConsoleCommands,
otherConsoleOptions
);
otherTruffleConsole = new Console(otherConsoleOptions);
});

it("accepts options.r", async function () {
Expand Down
8 changes: 4 additions & 4 deletions packages/truffle/test/scenarios/commands/develop.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,19 +78,19 @@ describe("truffle develop", function () {
[
{
cmd: "console",
expectedError: `ℹ️ : 'console' is not allowed within Truffle REPL`
expectedError: `ℹ️ : 'truffle console' is not allowed in Console environment.`
},
{
cmd: "CONSOLE",
expectedError: `ℹ️ : 'CONSOLE' is not allowed within Truffle REPL`
expectedError: `ℹ️ : 'truffle CONSOLE' is not allowed in Console environment.`
},
{
cmd: "develop",
expectedError: `ℹ️ : 'develop' is not allowed within Truffle REPL`
expectedError: `ℹ️ : 'truffle develop' is not allowed in Console environment.`
},
{
cmd: "alakazam",
expectedError: `ℹ️ : 'alakazam' is not a valid Truffle command`
expectedError: `ℹ️ : 'truffle alakazam' is not a valid truffle command.`
},
{
cmd: "",
Expand Down
4 changes: 2 additions & 2 deletions packages/truffle/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const webpack = require("webpack");
const pkg = require("./package.json");
const rootDir = path.join(__dirname, "../..");
const outputDir = path.join(__dirname, "build");
const commands = require("../core/lib/commands/commands");
const { validTruffleCommands } = require("../core/lib/commands/commands");
const truffleLibraryDirectory = path.join(
__dirname,
"../..",
Expand All @@ -27,7 +27,7 @@ const truffleRequireDistDirectory = path.join(

const ganacheConsoleSol = require.resolve("@ganache/console.log/console.sol");

const commandsEntries = commands.reduce((a, command) => {
const commandsEntries = validTruffleCommands.reduce((a, command) => {
a[command] = path.join(
__dirname,
"../..",
Expand Down

0 comments on commit 591d3ac

Please sign in to comment.