From 57291c435c2c7e2b3df41838a8f94ff957541bbb Mon Sep 17 00:00:00 2001 From: Patrick Kuo Date: Thu, 19 Apr 2018 21:22:04 +0100 Subject: [PATCH] =?UTF-8?q?ENT-1661=20Doorman=20crashes=20ungracefully=20w?= =?UTF-8?q?hen=20started=20with=20incorrect=20or=20=E2=80=A6=20(#747)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ENT-1661 Doorman crashes ungracefully when started with incorrect or no program arguments. Should display a meaningful message instead. --- .../registration-tool/build.gradle | 2 + .../corda/networkmanage/registration/Main.kt | 67 +++++++------------ .../registration/OptionParserTest.kt | 10 +-- .../configuration/ConfigFilePathArgsParser.kt | 23 +++++++ .../common/configuration/Configuration.kt | 28 -------- .../networkmanage/common/utils/ArgsParser.kt | 37 ++++++++++ .../corda/networkmanage/common/utils/Utils.kt | 5 -- .../corda/networkmanage/dev/Configuration.kt | 3 +- .../com/r3/corda/networkmanage/dev/Main.kt | 4 +- .../doorman/DoormanArgsParser.kt | 14 ++-- .../r3/corda/networkmanage/doorman/Main.kt | 8 +-- .../com/r3/corda/networkmanage/hsm/Main.kt | 10 +-- .../hsm/configuration/SigningServiceConfig.kt | 21 ++---- .../corda/networkmanage/hsm/generator/Main.kt | 4 +- .../tools/crr/submission/CRRToolArgsParser.kt | 16 +++++ .../tools/crr/submission/Configuration.kt | 21 ------ .../tools/crr/submission/Main.kt | 2 +- .../dev/GeneratorConfigurationTest.kt | 4 +- .../doorman/DoormanArgsParserTest.kt | 20 ++---- .../SigningServiceArgsParserTest.kt | 6 +- .../hsm/generator/GeneratorParametersTest.kt | 16 ++--- 21 files changed, 141 insertions(+), 180 deletions(-) create mode 100644 network-management/src/main/kotlin/com/r3/corda/networkmanage/common/configuration/ConfigFilePathArgsParser.kt delete mode 100644 network-management/src/main/kotlin/com/r3/corda/networkmanage/common/configuration/Configuration.kt create mode 100644 network-management/src/main/kotlin/com/r3/corda/networkmanage/common/utils/ArgsParser.kt create mode 100644 network-management/src/main/kotlin/com/r3/corda/networkmanage/tools/crr/submission/CRRToolArgsParser.kt delete mode 100644 network-management/src/main/kotlin/com/r3/corda/networkmanage/tools/crr/submission/Configuration.kt diff --git a/network-management/registration-tool/build.gradle b/network-management/registration-tool/build.gradle index 9ccb567445..c95fa84c15 100644 --- a/network-management/registration-tool/build.gradle +++ b/network-management/registration-tool/build.gradle @@ -68,6 +68,8 @@ publish { dependencies { compile project(':node') + // TODO: remove this when ArgsParser is moved into corda. + compile project(':network-management') testCompile 'junit:junit:4.12' testCompile "org.assertj:assertj-core:${assertj_version}" } diff --git a/network-management/registration-tool/src/main/kotlin/com/r3/corda/networkmanage/registration/Main.kt b/network-management/registration-tool/src/main/kotlin/com/r3/corda/networkmanage/registration/Main.kt index 53cb400af4..f4c051da8a 100644 --- a/network-management/registration-tool/src/main/kotlin/com/r3/corda/networkmanage/registration/Main.kt +++ b/network-management/registration-tool/src/main/kotlin/com/r3/corda/networkmanage/registration/Main.kt @@ -1,87 +1,74 @@ package com.r3.corda.networkmanage.registration +import com.r3.corda.networkmanage.common.utils.ArgsParser import com.r3.corda.networkmanage.registration.ToolOption.KeyCopierOption import com.r3.corda.networkmanage.registration.ToolOption.RegistrationOption -import joptsimple.OptionParser +import joptsimple.OptionSet import joptsimple.OptionSpecBuilder import joptsimple.util.PathConverter import joptsimple.util.PathProperties import net.corda.core.crypto.Crypto import java.nio.file.Path -import kotlin.system.exitProcess fun main(args: Array) { Crypto.registerProviders() // Required to register Providers first thing on boot. - val options = try { - parseOptions(*args) - } catch (e: ShowHelpException) { - e.errorMessage?.let(::println) - e.parser.printHelpOn(System.out) - exitProcess(0) - } + val options = ToolArgsParser().parseOrExit(*args, printHelpOn = System.out) when (options) { is RegistrationOption -> options.runRegistration() is KeyCopierOption -> options.copyKeystore() } } -fun parseOptions(vararg args: String): ToolOption { - val optionParser = OptionParser() - val helpOption = optionParser.acceptsAll(listOf("h", "help"), "show help").forHelp() +class ToolArgsParser : ArgsParser() { + private val importKeyStoreArg = optionParser.accepts("importkeystore") - val importKeyStoreArg = optionParser.accepts("importkeystore") - - val configFileArg = optionParser + private val configFileArg = optionParser .accepts("config-file", "Path to the registration config file") .availableUnless(importKeyStoreArg) .requiredUnless(importKeyStoreArg) .withRequiredArg() .withValuesConvertedBy(PathConverter(PathProperties.FILE_EXISTING)) - // key copy tool args - val destKeystorePathArg = optionParser.accepts("destkeystore", "Path to the destination keystore which the private key should be copied to") + private val destKeystorePathArg = optionParser.accepts("destkeystore", "Path to the destination keystore which the private key should be copied to") .requireOnlyIf(importKeyStoreArg) .withRequiredArg() .withValuesConvertedBy(PathConverter(PathProperties.FILE_EXISTING)) - val srcKeystorePathArg = optionParser.accepts("srckeystore", "Path to the source keystore containing the private key") + private val srcKeystorePathArg = optionParser.accepts("srckeystore", "Path to the source keystore containing the private key") .requireOnlyIf(importKeyStoreArg) .withRequiredArg() .withValuesConvertedBy(PathConverter(PathProperties.FILE_EXISTING)) - val destPasswordArg = optionParser.accepts("deststorepass", "Source keystore password. Read in from the console if not specified.") + private val destPasswordArg = optionParser.accepts("deststorepass", "Source keystore password. Read in from the console if not specified.") .availableIf(importKeyStoreArg) .withRequiredArg() - val srcPasswordArg = optionParser.accepts("srcstorepass", "Destination keystore password. Read in from the console if not specified.") + private val srcPasswordArg = optionParser.accepts("srcstorepass", "Destination keystore password. Read in from the console if not specified.") .availableIf(importKeyStoreArg) .withRequiredArg() - val destAliasArg = optionParser.accepts("destalias", "The alias under which the private key will be stored in the destination key store. If not provided then [srcalias] is used.") + private val destAliasArg = optionParser.accepts("destalias", "The alias under which the private key will be stored in the destination key store. If not provided then [srcalias] is used.") .availableIf(importKeyStoreArg) .withRequiredArg() - val srcAliasArg = optionParser.accepts("srcalias", "The alias under which the private key resides in the source key store") + private val srcAliasArg = optionParser.accepts("srcalias", "The alias under which the private key resides in the source key store") .requireOnlyIf(importKeyStoreArg) .withRequiredArg() - val optionSet = optionParser.parse(*args) - if (optionSet.has(helpOption)) { - throw ShowHelpException(optionParser) - } - - val isCopyKey = optionSet.has(importKeyStoreArg) - return if (isCopyKey) { - val srcKeystorePath = optionSet.valueOf(srcKeystorePathArg) - val targetKeystorePath = optionSet.valueOf(destKeystorePathArg) - val srcPassword = optionSet.valueOf(srcPasswordArg) - val destPassword = optionSet.valueOf(destPasswordArg) - val srcAlias = optionSet.valueOf(srcAliasArg) - val destAlias = optionSet.valueOf(destAliasArg) - KeyCopierOption(srcKeystorePath, targetKeystorePath, srcPassword, destPassword, srcAlias, destAlias) - } else { - val configFile = optionSet.valueOf(configFileArg) - RegistrationOption(configFile) + override fun parse(optionSet: OptionSet): ToolOption { + val isCopyKey = optionSet.has(importKeyStoreArg) + return if (isCopyKey) { + val srcKeystorePath = optionSet.valueOf(srcKeystorePathArg) + val targetKeystorePath = optionSet.valueOf(destKeystorePathArg) + val srcPassword = optionSet.valueOf(srcPasswordArg) + val destPassword = optionSet.valueOf(destPasswordArg) + val srcAlias = optionSet.valueOf(srcAliasArg) + val destAlias = optionSet.valueOf(destAliasArg) + KeyCopierOption(srcKeystorePath, targetKeystorePath, srcPassword, destPassword, srcAlias, destAlias) + } else { + val configFile = optionSet.valueOf(configFileArg) + RegistrationOption(configFile) + } } } @@ -97,8 +84,6 @@ sealed class ToolOption { val destinationAlias: String?) : ToolOption() } -class ShowHelpException(val parser: OptionParser, val errorMessage: String? = null) : Exception() - fun readPassword(fmt: String): String { return if (System.console() != null) { String(System.console().readPassword(fmt)) diff --git a/network-management/registration-tool/src/test/kotlin/com/r3/corda/networkmanage/registration/OptionParserTest.kt b/network-management/registration-tool/src/test/kotlin/com/r3/corda/networkmanage/registration/OptionParserTest.kt index 669c1220d9..8614bfa177 100644 --- a/network-management/registration-tool/src/test/kotlin/com/r3/corda/networkmanage/registration/OptionParserTest.kt +++ b/network-management/registration-tool/src/test/kotlin/com/r3/corda/networkmanage/registration/OptionParserTest.kt @@ -27,7 +27,7 @@ class OptionParserTest { @Test fun `parse registration args correctly`() { - val options = parseOptions("--config-file", "${tempDir / "test.file"}") as ToolOption.RegistrationOption + val options = ToolArgsParser().parseOrExit("--config-file", "${tempDir / "test.file"}") as ToolOption.RegistrationOption assertThat(options.configFile).isEqualTo(tempDir / "test.file") } @@ -40,7 +40,7 @@ class OptionParserTest { "--destkeystore", "${tempDir / "target.jks"}", "--deststorepass", "password2", "--srcalias", "testalias") - assertThatThrownBy { parseOptions(*keyCopyArgs, "--config-file", "test.file") } + assertThatThrownBy { ToolArgsParser().parseOrExit(*keyCopyArgs, "--config-file", "test.file", printHelpOn = null) } .isInstanceOf(OptionException::class.java) .hasMessageContaining("Option(s) [config-file] are unavailable given other options on the command line") } @@ -48,7 +48,7 @@ class OptionParserTest { @Test fun `key copy args should be unavailable in registration mode`() { assertThatThrownBy { - parseOptions("--config-file", "${tempDir / "test.file"}", "--srckeystore", "${tempDir / "source.jks"}") + ToolArgsParser().parseOrExit("--config-file", "${tempDir / "test.file"}", "--srckeystore", "${tempDir / "source.jks"}", printHelpOn = null) }.isInstanceOf(OptionException::class.java) .hasMessageContaining("Option(s) [srckeystore] are unavailable given other options on the command line") } @@ -63,7 +63,7 @@ class OptionParserTest { "--deststorepass", "password2", "--srcalias", "testalias", "--destalias", "testalias2") - assertThat(parseOptions(*keyCopyArgs)).isEqualTo(ToolOption.KeyCopierOption( + assertThat(ToolArgsParser().parseOrExit(*keyCopyArgs)).isEqualTo(ToolOption.KeyCopierOption( sourceFile = tempDir / "source.jks", destinationFile = tempDir / "target.jks", sourcePassword = "password1", @@ -80,7 +80,7 @@ class OptionParserTest { "--srckeystore", "${tempDir / "source.jks"}", "--destkeystore", "${tempDir / "target.jks"}", "--srcalias", "testalias") - assertThat(parseOptions(*keyCopyArgs)).isEqualTo(ToolOption.KeyCopierOption( + assertThat(ToolArgsParser().parseOrExit(*keyCopyArgs)).isEqualTo(ToolOption.KeyCopierOption( sourceFile = tempDir / "source.jks", destinationFile = tempDir / "target.jks", sourcePassword = null, diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/configuration/ConfigFilePathArgsParser.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/configuration/ConfigFilePathArgsParser.kt new file mode 100644 index 0000000000..1df0e4a504 --- /dev/null +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/configuration/ConfigFilePathArgsParser.kt @@ -0,0 +1,23 @@ +package com.r3.corda.networkmanage.common.configuration + +import com.r3.corda.networkmanage.common.utils.ArgsParser +import joptsimple.OptionSet +import joptsimple.util.PathConverter +import joptsimple.util.PathProperties +import java.nio.file.Path + +/** + * Parses key generator command line options. + */ +class ConfigFilePathArgsParser : ArgsParser() { + private val configFileArg = optionParser + .accepts("config-file", "The path to the config file") + .withRequiredArg() + .required() + .describedAs("filepath") + .withValuesConvertedBy(PathConverter(PathProperties.FILE_EXISTING)) + + override fun parse(optionSet: OptionSet): Path { + return optionSet.valueOf(configFileArg).toAbsolutePath() + } +} \ No newline at end of file diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/configuration/Configuration.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/configuration/Configuration.kt deleted file mode 100644 index 9167701826..0000000000 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/configuration/Configuration.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.r3.corda.networkmanage.common.configuration - -import com.r3.corda.networkmanage.common.utils.ShowHelpException -import joptsimple.OptionParser -import joptsimple.util.PathConverter -import joptsimple.util.PathProperties -import java.nio.file.Path - -/** - * Parses key generator command line options. - */ -fun parseCommandLine(vararg args: String): Path { - val optionParser = OptionParser() - val configFileArg = optionParser - .accepts("config-file", "The path to the config file") - .withRequiredArg() - .required() - .describedAs("filepath") - .withValuesConvertedBy(PathConverter(PathProperties.FILE_EXISTING)) - val helpOption = optionParser.acceptsAll(listOf("h", "help"), "show help").forHelp() - - val optionSet = optionParser.parse(*args) - // Print help and exit on help option or if there are missing options. - if (optionSet.has(helpOption) || !optionSet.has(configFileArg)) { - throw ShowHelpException(optionParser) - } - return optionSet.valueOf(configFileArg).toAbsolutePath() -} \ No newline at end of file diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/utils/ArgsParser.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/utils/ArgsParser.kt new file mode 100644 index 0000000000..0b94f2d262 --- /dev/null +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/utils/ArgsParser.kt @@ -0,0 +1,37 @@ +package com.r3.corda.networkmanage.common.utils + +import joptsimple.OptionException +import joptsimple.OptionParser +import joptsimple.OptionSet +import java.io.PrintStream +import kotlin.system.exitProcess + +// TODO: This class could be useful for the rest of the codebase. +abstract class ArgsParser { + protected val optionParser = OptionParser() + private val helpOption = optionParser.acceptsAll(listOf("h", "help"), "show help").forHelp() + + /** + If [printHelpOn] output stream is not null, this method will print help message and exit process + when encountered any error during args parsing, or when help flag is set. + */ + fun parseOrExit(vararg args: String, printHelpOn: PrintStream? = System.out): T { + val optionSet = try { + optionParser.parse(*args) + } catch (e: OptionException) { + printHelpOn?.let { + it.println(e.message ?: "Unable to parse arguments.") + optionParser.printHelpOn(it) + exitProcess(-1) + } + throw e + } + if (optionSet.has(helpOption)) { + printHelpOn?.let(optionParser::printHelpOn) + exitProcess(0) + } + return parse(optionSet) + } + + protected abstract fun parse(optionSet: OptionSet): T +} diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/utils/Utils.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/utils/Utils.kt index 5c408796c7..a95d79326a 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/utils/Utils.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/utils/Utils.kt @@ -13,9 +13,7 @@ package com.r3.corda.networkmanage.common.utils import com.typesafe.config.ConfigFactory import com.typesafe.config.ConfigParseOptions import com.typesafe.config.ConfigRenderOptions -import joptsimple.OptionParser import net.corda.core.CordaOID -import net.corda.core.crypto.sha256 import net.corda.core.internal.CertRole import net.corda.core.serialization.internal.SerializationEnvironmentImpl import net.corda.core.serialization.internal.nodeSerializationEnv @@ -34,7 +32,6 @@ import org.slf4j.LoggerFactory import java.nio.file.Path import java.security.KeyPair import java.security.PrivateKey -import java.security.PublicKey import java.security.cert.CertPath import java.security.cert.X509Certificate @@ -52,8 +49,6 @@ inline fun parseConfig(file: Path): T { return config.parseAs(strict = false) } -class ShowHelpException(val parser: OptionParser, val errorMessage: String? = null) : Exception() - fun buildCertPath(certPathBytes: ByteArray): CertPath = X509CertificateFactory().delegate.generateCertPath(certPathBytes.inputStream()) fun X509KeyStore.getCertPathAndKey(alias: String, privateKeyPassword: String): CertPathAndKey { diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/dev/Configuration.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/dev/Configuration.kt index cd92e249c1..70b5aa332a 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/dev/Configuration.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/dev/Configuration.kt @@ -38,8 +38,7 @@ fun parseParameters(configFile: Path?): GeneratorConfiguration { return if (configFile == null) { GeneratorConfiguration() } else { - ConfigFactory - .parseFile(configFile.toFile(), ConfigParseOptions.defaults().setAllowMissing(true)) + ConfigFactory.parseFile(configFile.toFile(), ConfigParseOptions.defaults().setAllowMissing(true)) .resolve() .parseAs() } diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/dev/Main.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/dev/Main.kt index 1de3ec8868..1644010a86 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/dev/Main.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/dev/Main.kt @@ -10,7 +10,7 @@ package com.r3.corda.networkmanage.dev -import com.r3.corda.networkmanage.common.configuration.parseCommandLine +import com.r3.corda.networkmanage.common.configuration.ConfigFilePathArgsParser import com.r3.corda.networkmanage.doorman.CORDA_X500_BASE import net.corda.core.crypto.Crypto import net.corda.core.internal.createDirectories @@ -34,7 +34,7 @@ private val logger = LogManager.getLogger("com.r3.corda.networkmanage.dev.Main") * Look for the 'certificates' directory. */ fun main(args: Array) { - run(parseParameters(parseCommandLine(*args))) + run(parseParameters(ConfigFilePathArgsParser().parseOrExit(*args))) } fun run(configuration: GeneratorConfiguration) { diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/DoormanArgsParser.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/DoormanArgsParser.kt index 6c60c07bf3..82121cf5d3 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/DoormanArgsParser.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/DoormanArgsParser.kt @@ -1,10 +1,10 @@ package com.r3.corda.networkmanage.doorman import com.google.common.primitives.Booleans -import com.r3.corda.networkmanage.common.utils.ShowHelpException +import com.r3.corda.networkmanage.common.utils.ArgsParser import com.typesafe.config.ConfigFactory import com.typesafe.config.ConfigParseOptions -import joptsimple.OptionParser +import joptsimple.OptionSet import joptsimple.util.EnumConverter import joptsimple.util.PathConverter import joptsimple.util.PathProperties @@ -14,9 +14,7 @@ import net.corda.nodeapi.internal.config.parseAs import java.nio.file.Path import java.time.Instant -class DoormanArgsParser { - private val optionParser = OptionParser() - private val helpOption = optionParser.acceptsAll(listOf("h", "help"), "show help").forHelp() +class DoormanArgsParser : ArgsParser() { private val configFileArg = optionParser .accepts("config-file", "The path to the config file") .withRequiredArg() @@ -37,11 +35,7 @@ class DoormanArgsParser { .accepts("trust-store-password", "Password for the generated network root trust store. Only applicable when operating in ${Mode.ROOT_KEYGEN} mode.") .withRequiredArg() - fun parse(vararg args: String): DoormanCmdLineOptions { - val optionSet = optionParser.parse(*args) - if (optionSet.has(helpOption)) { - throw ShowHelpException(optionParser) - } + override fun parse(optionSet: OptionSet): DoormanCmdLineOptions { val configFile = optionSet.valueOf(configFileArg) val mode = optionSet.valueOf(modeArg) val setNetworkParametersFile = optionSet.valueOf(setNetworkParametersArg) diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/Main.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/Main.kt index 05ee1efccf..f5fc6a5e78 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/Main.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/Main.kt @@ -31,13 +31,7 @@ fun main(args: Array) { } initialiseSerialization() - val cmdLineOptions = try { - DoormanArgsParser().parse(*args) - } catch (e: ShowHelpException) { - e.errorMessage?.let(::println) - e.parser.printHelpOn(System.out) - exitProcess(0) - } + val cmdLineOptions = DoormanArgsParser().parseOrExit(*args) val config = parseConfig(cmdLineOptions.configFile) diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/Main.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/Main.kt index 582161b1d7..fd622e9bcb 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/Main.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/Main.kt @@ -12,7 +12,6 @@ package com.r3.corda.networkmanage.hsm import com.jcabi.manifests.Manifests import com.r3.corda.networkmanage.common.persistence.configureDatabase -import com.r3.corda.networkmanage.common.utils.ShowHelpException import com.r3.corda.networkmanage.common.utils.initialiseSerialization import com.r3.corda.networkmanage.common.utils.parseConfig import com.r3.corda.networkmanage.hsm.configuration.ManualMode @@ -25,7 +24,6 @@ import org.apache.logging.log4j.LogManager import org.bouncycastle.jce.provider.BouncyCastleProvider import java.security.Security import javax.crypto.Cipher -import kotlin.system.exitProcess private val logger = LogManager.getLogger("com.r3.corda.networkmanage.hsm.Main") @@ -34,13 +32,7 @@ fun main(args: Array) { println("Signing Service Version: ${Manifests.read("Signing-Service-Version")}") } - val cmdLineOptions = try { - SigningServiceArgsParser().parse(*args) - } catch (e: ShowHelpException) { - e.errorMessage?.let(::println) - e.parser.printHelpOn(System.out) - exitProcess(0) - } + val cmdLineOptions = SigningServiceArgsParser().parseOrExit(*args) val config = parseConfig(cmdLineOptions.configFile) diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/configuration/SigningServiceConfig.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/configuration/SigningServiceConfig.kt index 1a96e87489..0dd6a44989 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/configuration/SigningServiceConfig.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/configuration/SigningServiceConfig.kt @@ -11,20 +11,15 @@ package com.r3.corda.networkmanage.hsm.configuration import com.google.common.primitives.Booleans -import com.r3.corda.networkmanage.common.utils.ShowHelpException +import com.r3.corda.networkmanage.common.utils.ArgsParser import com.r3.corda.networkmanage.hsm.authentication.AuthMode -import com.typesafe.config.ConfigFactory -import com.typesafe.config.ConfigParseOptions -import com.typesafe.config.ConfigRenderOptions -import joptsimple.OptionParser +import joptsimple.OptionSet import joptsimple.util.PathConverter import joptsimple.util.PathProperties import net.corda.core.internal.div import net.corda.core.utilities.NetworkHostAndPort -import net.corda.nodeapi.internal.config.parseAs import net.corda.nodeapi.internal.crypto.X509KeyStore import net.corda.nodeapi.internal.persistence.DatabaseConfig -import java.net.InetAddress import java.net.URL import java.nio.file.Path import java.nio.file.Paths @@ -61,7 +56,7 @@ data class DoormanCertificateConfig(val crlDistributionPoint: URL, val crlServerSocketAddress: NetworkHostAndPort, val crlUpdatePeriod: Long, val mode: ManualMode, - val keyGroup:String, + val keyGroup: String, val validDays: Int, val rootKeyStoreFile: Path, val rootKeyStorePassword: String, @@ -84,9 +79,7 @@ data class AuthParametersConfig(val mode: AuthMode, val keyFilePath: Path? = null, val threshold: Int) -class SigningServiceArgsParser { - private val optionParser = OptionParser() - private val helpOption = optionParser.acceptsAll(listOf("h", "help"), "show help").forHelp() +class SigningServiceArgsParser : ArgsParser() { private val baseDirArg = optionParser .accepts("basedir", "Overriding configuration filepath, default to current directory.") .withRequiredArg() @@ -97,11 +90,7 @@ class SigningServiceArgsParser { .withRequiredArg() .withValuesConvertedBy(PathConverter(PathProperties.FILE_EXISTING)) - fun parse(vararg args: String): SigningServiceCmdLineOptions { - val optionSet = optionParser.parse(*args) - if (optionSet.has(helpOption)) { - throw ShowHelpException(optionParser) - } + override fun parse(optionSet: OptionSet): SigningServiceCmdLineOptions { val baseDir = optionSet.valueOf(baseDirArg) val configFile = optionSet.valueOf(configFileArg) ?: baseDir / "signing_service.conf" return SigningServiceCmdLineOptions(baseDir, configFile) diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/Main.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/Main.kt index f8153ebe0b..e8ee62ebae 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/Main.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/generator/Main.kt @@ -10,7 +10,7 @@ package com.r3.corda.networkmanage.hsm.generator -import com.r3.corda.networkmanage.common.configuration.parseCommandLine +import com.r3.corda.networkmanage.common.configuration.ConfigFilePathArgsParser import com.r3.corda.networkmanage.hsm.authentication.CryptoServerProviderConfig import com.r3.corda.networkmanage.hsm.utils.mapCryptoServerException import net.corda.nodeapi.internal.crypto.CertificateType.ROOT_CA @@ -19,7 +19,7 @@ import org.apache.logging.log4j.LogManager private val logger = LogManager.getLogger("com.r3.corda.networkmanage.hsm.generator.Main") fun main(args: Array) { - run(parseParameters(parseCommandLine(*args))) + run(parseParameters(ConfigFilePathArgsParser().parseOrExit(*args))) } fun run(parameters: GeneratorParameters) { diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/tools/crr/submission/CRRToolArgsParser.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/tools/crr/submission/CRRToolArgsParser.kt new file mode 100644 index 0000000000..291c22acc4 --- /dev/null +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/tools/crr/submission/CRRToolArgsParser.kt @@ -0,0 +1,16 @@ +package com.r3.corda.networkmanage.tools.crr.submission + +import com.r3.corda.networkmanage.common.utils.ArgsParser +import joptsimple.OptionSet +import java.net.URL + +class CRRToolArgsParser : ArgsParser() { + private val submissionUrlArg = optionParser + .accepts("submission-url", "CRR submission endpoint.") + .withRequiredArg() + .required() + + override fun parse(optionSet: OptionSet): URL { + return URL(optionSet.valueOf(submissionUrlArg)) + } +} \ No newline at end of file diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/tools/crr/submission/Configuration.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/tools/crr/submission/Configuration.kt deleted file mode 100644 index 09ab159185..0000000000 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/tools/crr/submission/Configuration.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.r3.corda.networkmanage.tools.crr.submission - -import com.r3.corda.networkmanage.common.utils.ShowHelpException -import joptsimple.OptionParser -import java.net.URL - -fun parseSubmissionUrl(vararg args: String): URL { - val optionParser = OptionParser() - val submissionUrlArg = optionParser - .accepts("submission-url", "CRR submission endpoint.") - .withRequiredArg() - .required() - val helpOption = optionParser.acceptsAll(listOf("h", "help"), "show help").forHelp() - - val optionSet = optionParser.parse(*args) - // Print help and exit on help option or if there are missing options. - if (optionSet.has(helpOption) || !optionSet.has(submissionUrlArg)) { - throw ShowHelpException(optionParser) - } - return URL(optionSet.valueOf(submissionUrlArg)) -} \ No newline at end of file diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/tools/crr/submission/Main.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/tools/crr/submission/Main.kt index 8691737f55..6ffba6acf6 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/tools/crr/submission/Main.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/tools/crr/submission/Main.kt @@ -17,7 +17,7 @@ private val logger = LogManager.getLogger("com.r3.corda.networkmanage.common.too fun main(args: Array) { initialiseSerialization() try { - submit(parseSubmissionUrl(*args)) + submit(CRRToolArgsParser().parseOrExit(*args)) } catch (e: Exception) { logger.error("Error when submitting a certificate revocation request.", e) throw e diff --git a/network-management/src/test/kotlin/com/r3/corda/networkmanage/dev/GeneratorConfigurationTest.kt b/network-management/src/test/kotlin/com/r3/corda/networkmanage/dev/GeneratorConfigurationTest.kt index beebaa367c..f72d8cd4eb 100644 --- a/network-management/src/test/kotlin/com/r3/corda/networkmanage/dev/GeneratorConfigurationTest.kt +++ b/network-management/src/test/kotlin/com/r3/corda/networkmanage/dev/GeneratorConfigurationTest.kt @@ -10,7 +10,7 @@ package com.r3.corda.networkmanage.dev -import com.r3.corda.networkmanage.common.configuration.parseCommandLine +import com.r3.corda.networkmanage.common.configuration.ConfigFilePathArgsParser import net.corda.nodeapi.internal.DEV_CA_KEY_STORE_FILE import net.corda.nodeapi.internal.DEV_CA_KEY_STORE_PASS import net.corda.nodeapi.internal.DEV_CA_TRUST_STORE_FILE @@ -31,7 +31,7 @@ class GeneratorConfigurationTest { @Test fun `config file is parsed correctly`() { - val config = parseParameters(parseCommandLine("--config-file", configPath)) + val config = parseParameters(ConfigFilePathArgsParser().parseOrExit("--config-file", configPath)) assertEquals(GeneratorConfiguration.DEFAULT_DIRECTORY, config.directory) assertEquals(DEV_CA_KEY_STORE_FILE, config.keyStoreFileName) assertEquals(DEV_CA_KEY_STORE_PASS, config.keyStorePass) diff --git a/network-management/src/test/kotlin/com/r3/corda/networkmanage/doorman/DoormanArgsParserTest.kt b/network-management/src/test/kotlin/com/r3/corda/networkmanage/doorman/DoormanArgsParserTest.kt index d949fce6b3..eb53a7ba48 100644 --- a/network-management/src/test/kotlin/com/r3/corda/networkmanage/doorman/DoormanArgsParserTest.kt +++ b/network-management/src/test/kotlin/com/r3/corda/networkmanage/doorman/DoormanArgsParserTest.kt @@ -10,7 +10,6 @@ package com.r3.corda.networkmanage.doorman -import com.r3.corda.networkmanage.common.utils.ShowHelpException import joptsimple.OptionException import org.assertj.core.api.Assertions.assertThatThrownBy import org.junit.Test @@ -26,39 +25,32 @@ class DoormanArgsParserTest { @Test fun `should fail when network parameters file is missing`() { assertThatThrownBy { - argsParser.parse("--config-file", validConfigPath, "--set-network-parameters", "not-here") + argsParser.parseOrExit("--config-file", validConfigPath, "--set-network-parameters", "not-here") }.hasMessageContaining("not-here") } @Test fun `should fail when config file is missing`() { assertThatThrownBy { - argsParser.parse("--config-file", "not-existing-file") + argsParser.parseOrExit("--config-file", "not-existing-file") }.hasMessageContaining("not-existing-file") } - @Test - fun `should throw ShowHelpException when help option is passed on the command line`() { - assertFailsWith { - argsParser.parse("-h") - } - } - @Test fun `should parse trust store password correctly`() { - val parameter = argsParser.parse("--config-file", validConfigPath, "--mode", "ROOT_KEYGEN", "--trust-store-password", "testPassword") + val parameter = argsParser.parseOrExit("--config-file", validConfigPath, "--mode", "ROOT_KEYGEN", "--trust-store-password", "testPassword") assertEquals("testPassword", parameter.trustStorePassword) assertFailsWith { - argsParser.parse("--trust-store-password") + argsParser.parseOrExit("--trust-store-password", printHelpOn = null) } // Should fail if password is provided in mode other then root keygen. assertFailsWith { - argsParser.parse("--config-file", validConfigPath, "--trust-store-password", "testPassword") + argsParser.parseOrExit("--config-file", validConfigPath, "--trust-store-password", "testPassword") } // trust store password is optional. - assertNull(argsParser.parse("--config-file", validConfigPath).trustStorePassword) + assertNull(argsParser.parseOrExit("--config-file", validConfigPath).trustStorePassword) } } diff --git a/network-management/src/test/kotlin/com/r3/corda/networkmanage/hsm/configuration/SigningServiceArgsParserTest.kt b/network-management/src/test/kotlin/com/r3/corda/networkmanage/hsm/configuration/SigningServiceArgsParserTest.kt index 630b8d4f4e..0b1d40ec6c 100644 --- a/network-management/src/test/kotlin/com/r3/corda/networkmanage/hsm/configuration/SigningServiceArgsParserTest.kt +++ b/network-management/src/test/kotlin/com/r3/corda/networkmanage/hsm/configuration/SigningServiceArgsParserTest.kt @@ -26,7 +26,7 @@ class SigningServiceArgsParserTest : TestBase() { @Test fun `doorman-based config file is parsed correctly`() { - val cmdLineOptions = argsParser.parse("--config-file", doormanConfigPath) + val cmdLineOptions = argsParser.parseOrExit("--config-file", doormanConfigPath) val config = parseConfig(cmdLineOptions.configFile) assertEquals("3001@192.168.0.1", config.device) val doormanCertParameters = config.doorman!! @@ -37,7 +37,7 @@ class SigningServiceArgsParserTest : TestBase() { @Test fun `networkmap-based config file is parsed correctly`() { - val cmdLineOptions = argsParser.parse("--config-file", networkMapConfigPath) + val cmdLineOptions = argsParser.parseOrExit("--config-file", networkMapConfigPath) val config = parseConfig(cmdLineOptions.configFile) assertEquals("3001@192.168.0.1", config.device) val networkMapConfig = config.networkMap!! @@ -51,7 +51,7 @@ class SigningServiceArgsParserTest : TestBase() { @Test fun `should fail when config file is missing`() { assertThatThrownBy { - argsParser.parse("--config-file", "not-existing-file") + argsParser.parseOrExit("--config-file", "not-existing-file") }.hasMessageContaining("not-existing-file") } } diff --git a/network-management/src/test/kotlin/com/r3/corda/networkmanage/hsm/generator/GeneratorParametersTest.kt b/network-management/src/test/kotlin/com/r3/corda/networkmanage/hsm/generator/GeneratorParametersTest.kt index 1bf28557ca..517ed44644 100644 --- a/network-management/src/test/kotlin/com/r3/corda/networkmanage/hsm/generator/GeneratorParametersTest.kt +++ b/network-management/src/test/kotlin/com/r3/corda/networkmanage/hsm/generator/GeneratorParametersTest.kt @@ -10,8 +10,7 @@ package com.r3.corda.networkmanage.hsm.generator -import com.r3.corda.networkmanage.common.configuration.parseCommandLine -import com.r3.corda.networkmanage.common.utils.ShowHelpException +import com.r3.corda.networkmanage.common.configuration.ConfigFilePathArgsParser import com.typesafe.config.ConfigException import joptsimple.OptionException import net.corda.nodeapi.internal.crypto.CertificateType @@ -31,22 +30,15 @@ class GeneratorParametersTest { @Test fun `should fail when config file is missing`() { val message = assertFailsWith { - parseCommandLine("--config-file", "not-existing-file") + ConfigFilePathArgsParser().parseOrExit("--config-file", "not-existing-file") }.message Assertions.assertThat(message).contains("not-existing-file") } - @Test - fun `should throw ShowHelpException when help option is passed on the command line`() { - assertFailsWith { - parseCommandLine("-h") - } - } - @Test fun `should fail when config is invalid`() { assertFailsWith { - parseParameters(parseCommandLine("--config-file", invalidConfigPath)) + parseParameters(ConfigFilePathArgsParser().parseOrExit("--config-file", invalidConfigPath)) } } @@ -71,6 +63,6 @@ class GeneratorParametersTest { } private fun parseCommandLineAndGetParameters(): GeneratorParameters { - return parseParameters(parseCommandLine(*validArgs)) + return parseParameters(ConfigFilePathArgsParser().parseOrExit(*validArgs)) } } \ No newline at end of file