|
|
9805a3 |
From ad1c8a07230c9e0ba26da54fa383ecefde949cb5 Mon Sep 17 00:00:00 2001
|
|
|
9805a3 |
From: Marian Koncek <mkoncek@redhat.com>
|
|
|
9805a3 |
Date: Fri, 8 Apr 2022 11:55:26 +0200
|
|
|
9805a3 |
Subject: [PATCH] Unconditionally single quote executable and arguments
|
|
|
9805a3 |
|
|
|
9805a3 |
Upstream: https://github.com/apache/maven-shared-utils/pull/40/commits
|
|
|
9805a3 |
|
|
|
9805a3 |
---
|
|
|
9805a3 |
.../shared/utils/cli/shell/BourneShell.java | 45 ++++++++-----------
|
|
|
9805a3 |
.../maven/shared/utils/cli/shell/Shell.java | 43 ++++++++++++------
|
|
|
9805a3 |
.../utils/cli/shell/BourneShellTest.java | 35 ++++++++++-----
|
|
|
9805a3 |
3 files changed, 73 insertions(+), 50 deletions(-)
|
|
|
9805a3 |
|
|
|
9805a3 |
diff --git a/src/main/java/org/apache/maven/shared/utils/cli/shell/BourneShell.java b/src/main/java/org/apache/maven/shared/utils/cli/shell/BourneShell.java
|
|
|
9805a3 |
index 845e4a4..fc4984a 100644
|
|
|
9805a3 |
--- a/src/main/java/org/apache/maven/shared/utils/cli/shell/BourneShell.java
|
|
|
9805a3 |
+++ b/src/main/java/org/apache/maven/shared/utils/cli/shell/BourneShell.java
|
|
|
9805a3 |
@@ -23,7 +23,6 @@ package org.apache.maven.shared.utils.cli.shell;
|
|
|
9805a3 |
import java.util.ArrayList;
|
|
|
9805a3 |
import java.util.List;
|
|
|
9805a3 |
import org.apache.maven.shared.utils.Os;
|
|
|
9805a3 |
-import org.apache.maven.shared.utils.StringUtils;
|
|
|
9805a3 |
|
|
|
9805a3 |
/**
|
|
|
9805a3 |
* @author Jason van Zyl
|
|
|
9805a3 |
@@ -31,14 +30,12 @@ import org.apache.maven.shared.utils.StringUtils;
|
|
|
9805a3 |
public class BourneShell
|
|
|
9805a3 |
extends Shell
|
|
|
9805a3 |
{
|
|
|
9805a3 |
- private static final char[] BASH_QUOTING_TRIGGER_CHARS =
|
|
|
9805a3 |
- { ' ', '$', ';', '&', '|', '<', '>', '*', '?', '(', ')', '[', ']', '{', '}', '`' };
|
|
|
9805a3 |
-
|
|
|
9805a3 |
public BourneShell()
|
|
|
9805a3 |
{
|
|
|
9805a3 |
+ setUnconditionalQuoting( true );
|
|
|
9805a3 |
setShellCommand( "/bin/sh" );
|
|
|
9805a3 |
setArgumentQuoteDelimiter( '\'' );
|
|
|
9805a3 |
- setExecutableQuoteDelimiter( '\"' );
|
|
|
9805a3 |
+ setExecutableQuoteDelimiter( '\'' );
|
|
|
9805a3 |
setSingleQuotedArgumentEscaped( true );
|
|
|
9805a3 |
setSingleQuotedExecutableEscaped( false );
|
|
|
9805a3 |
setQuotedExecutableEnabled( true );
|
|
|
9805a3 |
@@ -54,7 +51,7 @@ public class BourneShell
|
|
|
9805a3 |
return super.getExecutable();
|
|
|
9805a3 |
}
|
|
|
9805a3 |
|
|
|
9805a3 |
- return unifyQuotes( super.getExecutable() );
|
|
|
9805a3 |
+ return quoteOneItem( super.getExecutable(), true );
|
|
|
9805a3 |
}
|
|
|
9805a3 |
|
|
|
9805a3 |
public List<String> getShellArgsList()
|
|
|
9805a3 |
@@ -104,46 +101,40 @@ public class BourneShell
|
|
|
9805a3 |
StringBuilder sb = new StringBuilder();
|
|
|
9805a3 |
sb.append( "cd " );
|
|
|
9805a3 |
|
|
|
9805a3 |
- sb.append( unifyQuotes( dir ) );
|
|
|
9805a3 |
+ sb.append( quoteOneItem( dir, false ) );
|
|
|
9805a3 |
sb.append( " && " );
|
|
|
9805a3 |
|
|
|
9805a3 |
return sb.toString();
|
|
|
9805a3 |
}
|
|
|
9805a3 |
|
|
|
9805a3 |
- protected char[] getQuotingTriggerChars()
|
|
|
9805a3 |
- {
|
|
|
9805a3 |
- return BASH_QUOTING_TRIGGER_CHARS;
|
|
|
9805a3 |
- }
|
|
|
9805a3 |
-
|
|
|
9805a3 |
/**
|
|
|
9805a3 |
* Unify quotes in a path for the Bourne Shell.
|
|
|
9805a3 |
*
|
|
|
9805a3 |
*
|
|
|
9805a3 |
- * BourneShell.unifyQuotes(null) = null
|
|
|
9805a3 |
- * BourneShell.unifyQuotes("") = (empty)
|
|
|
9805a3 |
- * BourneShell.unifyQuotes("/test/quotedpath'abc") = /test/quotedpath\'abc
|
|
|
9805a3 |
- * BourneShell.unifyQuotes("/test/quoted path'abc") = "/test/quoted path'abc"
|
|
|
9805a3 |
- * BourneShell.unifyQuotes("/test/quotedpath\"abc") = "/test/quotedpath\"abc"
|
|
|
9805a3 |
- * BourneShell.unifyQuotes("/test/quoted path\"abc") = "/test/quoted path\"abc"
|
|
|
9805a3 |
- * BourneShell.unifyQuotes("/test/quotedpath\"'abc") = "/test/quotedpath\"'abc"
|
|
|
9805a3 |
- * BourneShell.unifyQuotes("/test/quoted path\"'abc") = "/test/quoted path\"'abc"
|
|
|
9805a3 |
+ * BourneShell.quoteOneItem(null) = null
|
|
|
9805a3 |
+ * BourneShell.quoteOneItem("") = ''
|
|
|
9805a3 |
+ * BourneShell.quoteOneItem("/test/quotedpath'abc") = '/test/quotedpath'"'"'abc'
|
|
|
9805a3 |
+ * BourneShell.quoteOneItem("/test/quoted path'abc") = '/test/quoted pat'"'"'habc'
|
|
|
9805a3 |
+ * BourneShell.quoteOneItem("/test/quotedpath\"abc") = '/test/quotedpath"abc'
|
|
|
9805a3 |
+ * BourneShell.quoteOneItem("/test/quoted path\"abc") = '/test/quoted path"abc'
|
|
|
9805a3 |
+ * BourneShell.quoteOneItem("/test/quotedpath\"'abc") = '/test/quotedpath"'"'"'abc'
|
|
|
9805a3 |
+ * BourneShell.quoteOneItem("/test/quoted path\"'abc") = '/test/quoted path"'"'"'abc'
|
|
|
9805a3 |
*
|
|
|
9805a3 |
*
|
|
|
9805a3 |
* @param path not null path.
|
|
|
9805a3 |
* @return the path unified correctly for the Bourne shell.
|
|
|
9805a3 |
*/
|
|
|
9805a3 |
- private static String unifyQuotes( String path )
|
|
|
9805a3 |
+ protected String quoteOneItem( String path, boolean isExecutable )
|
|
|
9805a3 |
{
|
|
|
9805a3 |
if ( path == null )
|
|
|
9805a3 |
{
|
|
|
9805a3 |
return null;
|
|
|
9805a3 |
}
|
|
|
9805a3 |
|
|
|
9805a3 |
- if ( path.indexOf( ' ' ) == -1 && path.indexOf( '\'' ) != -1 && path.indexOf( '"' ) == -1 )
|
|
|
9805a3 |
- {
|
|
|
9805a3 |
- return StringUtils.escape( path );
|
|
|
9805a3 |
- }
|
|
|
9805a3 |
-
|
|
|
9805a3 |
- return StringUtils.quoteAndEscape( path, '\"', BASH_QUOTING_TRIGGER_CHARS );
|
|
|
9805a3 |
+ StringBuilder sb = new StringBuilder();
|
|
|
9805a3 |
+ sb.append( "'" );
|
|
|
9805a3 |
+ sb.append( path.replace( "'", "'\"'\"'" ) );
|
|
|
9805a3 |
+ sb.append( "'" );
|
|
|
9805a3 |
+ return sb.toString();
|
|
|
9805a3 |
}
|
|
|
9805a3 |
}
|
|
|
9805a3 |
diff --git a/src/main/java/org/apache/maven/shared/utils/cli/shell/Shell.java b/src/main/java/org/apache/maven/shared/utils/cli/shell/Shell.java
|
|
|
9805a3 |
index 70dddd0..2b889ff 100644
|
|
|
9805a3 |
--- a/src/main/java/org/apache/maven/shared/utils/cli/shell/Shell.java
|
|
|
9805a3 |
+++ b/src/main/java/org/apache/maven/shared/utils/cli/shell/Shell.java
|
|
|
9805a3 |
@@ -50,6 +50,8 @@ public class Shell
|
|
|
9805a3 |
|
|
|
9805a3 |
private boolean quotedArgumentsEnabled = true;
|
|
|
9805a3 |
|
|
|
9805a3 |
+ private boolean unconditionalQuoting = false;
|
|
|
9805a3 |
+
|
|
|
9805a3 |
private String executable;
|
|
|
9805a3 |
|
|
|
9805a3 |
private String workingDir;
|
|
|
9805a3 |
@@ -113,6 +115,19 @@ public class Shell
|
|
|
9805a3 |
}
|
|
|
9805a3 |
}
|
|
|
9805a3 |
|
|
|
9805a3 |
+ protected String quoteOneItem( String inputString, boolean isExecutable )
|
|
|
9805a3 |
+ {
|
|
|
9805a3 |
+ char[] escapeChars = getEscapeChars( isSingleQuotedExecutableEscaped(), isDoubleQuotedExecutableEscaped() );
|
|
|
9805a3 |
+ return StringUtils.quoteAndEscape(
|
|
|
9805a3 |
+ inputString,
|
|
|
9805a3 |
+ isExecutable ? getExecutableQuoteDelimiter() : getArgumentQuoteDelimiter(),
|
|
|
9805a3 |
+ escapeChars,
|
|
|
9805a3 |
+ getQuotingTriggerChars(),
|
|
|
9805a3 |
+ '\\',
|
|
|
9805a3 |
+ unconditionalQuoting
|
|
|
9805a3 |
+ );
|
|
|
9805a3 |
+ }
|
|
|
9805a3 |
+
|
|
|
9805a3 |
/**
|
|
|
9805a3 |
* Get the command line for the provided executable and arguments in this shell
|
|
|
9805a3 |
*
|
|
|
9805a3 |
@@ -125,12 +140,12 @@ public class Shell
|
|
|
9805a3 |
return getRawCommandLine( executable, arguments );
|
|
|
9805a3 |
}
|
|
|
9805a3 |
|
|
|
9805a3 |
- List<String> getRawCommandLine( String executable, String... arguments )
|
|
|
9805a3 |
+ List<String> getRawCommandLine( String executableParameter, String... arguments )
|
|
|
9805a3 |
{
|
|
|
9805a3 |
List<String> commandLine = new ArrayList<String>();
|
|
|
9805a3 |
StringBuilder sb = new StringBuilder();
|
|
|
9805a3 |
|
|
|
9805a3 |
- if ( executable != null )
|
|
|
9805a3 |
+ if ( executableParameter != null )
|
|
|
9805a3 |
{
|
|
|
9805a3 |
String preamble = getExecutionPreamble();
|
|
|
9805a3 |
if ( preamble != null )
|
|
|
9805a3 |
@@ -140,15 +155,11 @@ public class Shell
|
|
|
9805a3 |
|
|
|
9805a3 |
if ( isQuotedExecutableEnabled() )
|
|
|
9805a3 |
{
|
|
|
9805a3 |
- char[] escapeChars =
|
|
|
9805a3 |
- getEscapeChars( isSingleQuotedExecutableEscaped(), isDoubleQuotedExecutableEscaped() );
|
|
|
9805a3 |
-
|
|
|
9805a3 |
- sb.append( StringUtils.quoteAndEscape( getExecutable(), getExecutableQuoteDelimiter(), escapeChars,
|
|
|
9805a3 |
- getQuotingTriggerChars(), '\\', false ) );
|
|
|
9805a3 |
+ sb.append( quoteOneItem( executableParameter, true ) );
|
|
|
9805a3 |
}
|
|
|
9805a3 |
else
|
|
|
9805a3 |
{
|
|
|
9805a3 |
- sb.append( getExecutable() );
|
|
|
9805a3 |
+ sb.append( executableParameter );
|
|
|
9805a3 |
}
|
|
|
9805a3 |
}
|
|
|
9805a3 |
for ( String argument : arguments )
|
|
|
9805a3 |
@@ -160,10 +171,7 @@ public class Shell
|
|
|
9805a3 |
|
|
|
9805a3 |
if ( isQuotedArgumentsEnabled() )
|
|
|
9805a3 |
{
|
|
|
9805a3 |
- char[] escapeChars = getEscapeChars( isSingleQuotedArgumentEscaped(), isDoubleQuotedArgumentEscaped() );
|
|
|
9805a3 |
-
|
|
|
9805a3 |
- sb.append( StringUtils.quoteAndEscape( argument, getArgumentQuoteDelimiter(), escapeChars,
|
|
|
9805a3 |
- getQuotingTriggerChars(), '\\', false ) );
|
|
|
9805a3 |
+ sb.append( quoteOneItem( argument, false ) );
|
|
|
9805a3 |
}
|
|
|
9805a3 |
else
|
|
|
9805a3 |
{
|
|
|
9805a3 |
@@ -268,7 +276,7 @@ public class Shell
|
|
|
9805a3 |
commandLine.addAll( getShellArgsList() );
|
|
|
9805a3 |
}
|
|
|
9805a3 |
|
|
|
9805a3 |
- commandLine.addAll( getCommandLine( getExecutable(), arguments ) );
|
|
|
9805a3 |
+ commandLine.addAll( getCommandLine( executable, arguments ) );
|
|
|
9805a3 |
|
|
|
9805a3 |
return commandLine;
|
|
|
9805a3 |
|
|
|
9805a3 |
@@ -368,4 +376,13 @@ public class Shell
|
|
|
9805a3 |
this.singleQuotedExecutableEscaped = singleQuotedExecutableEscaped;
|
|
|
9805a3 |
}
|
|
|
9805a3 |
|
|
|
9805a3 |
+ public boolean isUnconditionalQuoting()
|
|
|
9805a3 |
+ {
|
|
|
9805a3 |
+ return unconditionalQuoting;
|
|
|
9805a3 |
+ }
|
|
|
9805a3 |
+
|
|
|
9805a3 |
+ public void setUnconditionalQuoting( boolean unconditionalQuoting )
|
|
|
9805a3 |
+ {
|
|
|
9805a3 |
+ this.unconditionalQuoting = unconditionalQuoting;
|
|
|
9805a3 |
+ }
|
|
|
9805a3 |
}
|
|
|
9805a3 |
diff --git a/src/test/java/org/apache/maven/shared/utils/cli/shell/BourneShellTest.java b/src/test/java/org/apache/maven/shared/utils/cli/shell/BourneShellTest.java
|
|
|
9805a3 |
index 741f81c..5509cea 100644
|
|
|
9805a3 |
--- a/src/test/java/org/apache/maven/shared/utils/cli/shell/BourneShellTest.java
|
|
|
9805a3 |
+++ b/src/test/java/org/apache/maven/shared/utils/cli/shell/BourneShellTest.java
|
|
|
9805a3 |
@@ -45,7 +45,7 @@ public class BourneShellTest
|
|
|
9805a3 |
|
|
|
9805a3 |
String executable = StringUtils.join( sh.getShellCommandLine( new String[]{} ).iterator(), " " );
|
|
|
9805a3 |
|
|
|
9805a3 |
- assertEquals( "/bin/sh -c cd /usr/local/bin && chmod", executable );
|
|
|
9805a3 |
+ assertEquals( "/bin/sh -c cd '/usr/local/bin' && 'chmod'", executable );
|
|
|
9805a3 |
}
|
|
|
9805a3 |
|
|
|
9805a3 |
public void testQuoteWorkingDirectoryAndExecutable_WDPathWithSingleQuotes()
|
|
|
9805a3 |
@@ -57,7 +57,7 @@ public class BourneShellTest
|
|
|
9805a3 |
|
|
|
9805a3 |
String executable = StringUtils.join( sh.getShellCommandLine( new String[]{} ).iterator(), " " );
|
|
|
9805a3 |
|
|
|
9805a3 |
- assertEquals( "/bin/sh -c cd \"/usr/local/\'something else\'\" && chmod", executable );
|
|
|
9805a3 |
+ assertEquals( "/bin/sh -c cd '/usr/local/'\"'\"'something else'\"'\"'' && 'chmod'", executable );
|
|
|
9805a3 |
}
|
|
|
9805a3 |
|
|
|
9805a3 |
public void testQuoteWorkingDirectoryAndExecutable_WDPathWithSingleQuotes_BackslashFileSep()
|
|
|
9805a3 |
@@ -69,7 +69,7 @@ public class BourneShellTest
|
|
|
9805a3 |
|
|
|
9805a3 |
String executable = StringUtils.join( sh.getShellCommandLine( new String[]{} ).iterator(), " " );
|
|
|
9805a3 |
|
|
|
9805a3 |
- assertEquals( "/bin/sh -c cd \"\\usr\\local\\\'something else\'\" && chmod", executable );
|
|
|
9805a3 |
+ assertEquals( "/bin/sh -c cd '\\usr\\local\\'\"'\"'something else'\"'\"'' && 'chmod'", executable );
|
|
|
9805a3 |
}
|
|
|
9805a3 |
|
|
|
9805a3 |
public void testPreserveSingleQuotesOnArgument()
|
|
|
9805a3 |
@@ -79,13 +79,13 @@ public class BourneShellTest
|
|
|
9805a3 |
sh.setWorkingDirectory( "/usr/bin" );
|
|
|
9805a3 |
sh.setExecutable( "chmod" );
|
|
|
9805a3 |
|
|
|
9805a3 |
- String[] args = { "\'some arg with spaces\'" };
|
|
|
9805a3 |
+ String[] args = { "\"some arg with spaces\"" };
|
|
|
9805a3 |
|
|
|
9805a3 |
List<String> shellCommandLine = sh.getShellCommandLine( args );
|
|
|
9805a3 |
|
|
|
9805a3 |
String cli = StringUtils.join( shellCommandLine.iterator(), " " );
|
|
|
9805a3 |
System.out.println( cli );
|
|
|
9805a3 |
- assertTrue( cli.endsWith( args[0] ) );
|
|
|
9805a3 |
+ assertTrue( cli.endsWith( "'\"some arg with spaces\"'" ) );
|
|
|
9805a3 |
}
|
|
|
9805a3 |
|
|
|
9805a3 |
public void testAddSingleQuotesOnArgumentWithSpaces()
|
|
|
9805a3 |
@@ -101,7 +101,21 @@ public class BourneShellTest
|
|
|
9805a3 |
|
|
|
9805a3 |
String cli = StringUtils.join( shellCommandLine.iterator(), " " );
|
|
|
9805a3 |
System.out.println( cli );
|
|
|
9805a3 |
- assertTrue( cli.endsWith( "\'" + args[0] + "\'" ) );
|
|
|
9805a3 |
+ assertTrue( cli.endsWith("'some arg with spaces'"));
|
|
|
9805a3 |
+ }
|
|
|
9805a3 |
+
|
|
|
9805a3 |
+ public void testAddArgumentWithSingleQuote()
|
|
|
9805a3 |
+ {
|
|
|
9805a3 |
+ Shell sh = newShell();
|
|
|
9805a3 |
+
|
|
|
9805a3 |
+ sh.setWorkingDirectory( "/usr/bin" );
|
|
|
9805a3 |
+ sh.setExecutable( "chmod" );
|
|
|
9805a3 |
+
|
|
|
9805a3 |
+ String[] args = { "arg'withquote" };
|
|
|
9805a3 |
+
|
|
|
9805a3 |
+ List<String> shellCommandLine = sh.getShellCommandLine( args );
|
|
|
9805a3 |
+
|
|
|
9805a3 |
+ assertEquals("cd '/usr/bin' && 'chmod' 'arg'\"'\"'withquote'", shellCommandLine.get(shellCommandLine.size() - 1));
|
|
|
9805a3 |
}
|
|
|
9805a3 |
|
|
|
9805a3 |
public void testArgumentsWithsemicolon()
|
|
|
9805a3 |
@@ -120,7 +134,7 @@ public class BourneShellTest
|
|
|
9805a3 |
|
|
|
9805a3 |
String cli = StringUtils.join( shellCommandLine.iterator(), " " );
|
|
|
9805a3 |
System.out.println( cli );
|
|
|
9805a3 |
- assertTrue( cli.endsWith( "\'" + args[0] + "\'" ) );
|
|
|
9805a3 |
+ assertTrue( cli.endsWith( "';some&argwithunix$chars'" ) );
|
|
|
9805a3 |
|
|
|
9805a3 |
Commandline commandline = new Commandline( newShell() );
|
|
|
9805a3 |
commandline.setExecutable( "chmod" );
|
|
|
9805a3 |
@@ -133,7 +147,7 @@ public class BourneShellTest
|
|
|
9805a3 |
|
|
|
9805a3 |
assertEquals( "/bin/sh", lines.get( 0 ) );
|
|
|
9805a3 |
assertEquals( "-c", lines.get( 1 ) );
|
|
|
9805a3 |
- assertEquals( "chmod --password ';password'", lines.get( 2 ) );
|
|
|
9805a3 |
+ assertEquals( "'chmod' '--password' ';password'", lines.get( 2 ) );
|
|
|
9805a3 |
|
|
|
9805a3 |
commandline = new Commandline( newShell() );
|
|
|
9805a3 |
commandline.setExecutable( "chmod" );
|
|
|
9805a3 |
@@ -145,7 +159,7 @@ public class BourneShellTest
|
|
|
9805a3 |
|
|
|
9805a3 |
assertEquals( "/bin/sh", lines.get( 0) );
|
|
|
9805a3 |
assertEquals( "-c", lines.get( 1 ) );
|
|
|
9805a3 |
- assertEquals( "chmod --password ';password'", lines.get( 2 ) );
|
|
|
9805a3 |
+ assertEquals( "'chmod' '--password' ';password'", lines.get( 2 ) );
|
|
|
9805a3 |
|
|
|
9805a3 |
commandline = new Commandline( new CmdShell() );
|
|
|
9805a3 |
commandline.getShell().setQuotedArgumentsEnabled( true );
|
|
|
9805a3 |
@@ -187,13 +201,14 @@ public class BourneShellTest
|
|
|
9805a3 |
commandline.createArg().setValue( "{" );
|
|
|
9805a3 |
commandline.createArg().setValue( "}" );
|
|
|
9805a3 |
commandline.createArg().setValue( "`" );
|
|
|
9805a3 |
+ commandline.createArg().setValue( "#" );
|
|
|
9805a3 |
|
|
|
9805a3 |
List<String> lines = commandline.getShell().getShellCommandLine( commandline.getArguments() );
|
|
|
9805a3 |
System.out.println( lines );
|
|
|
9805a3 |
|
|
|
9805a3 |
assertEquals( "/bin/sh", lines.get( 0 ) );
|
|
|
9805a3 |
assertEquals( "-c", lines.get( 1 ) );
|
|
|
9805a3 |
- assertEquals( "chmod ' ' '|' '&&' '||' ';' ';;' '&' '()' '<' '<<' '>' '>>' '*' '?' '[' ']' '{' '}' '`'",
|
|
|
9805a3 |
+ assertEquals( "'chmod' ' ' '|' '&&' '||' ';' ';;' '&' '()' '<' '<<' '>' '>>' '*' '?' '[' ']' '{' '}' '`' '#'",
|
|
|
9805a3 |
lines.get( 2 ) );
|
|
|
9805a3 |
}
|
|
|
9805a3 |
|
|
|
9805a3 |
--
|
|
|
9805a3 |
2.35.1
|
|
|
9805a3 |
|