diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index 37838044e4..c03711555d 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -112,7 +112,8 @@ Unreleased * ``WireTransaction.Companion.createComponentGroups`` has been marked as ``@CordaInternal``. It was never intended to be public and was already internal for Kotlin code. -* RPC server will now mask internal errors to RPC clients if not in devMode. ``Throwable``s implementing ``ClientRelevantError`` will continue to be propagated to clients. +* RPC server will now mask internal errors to RPC clients if not in devMode. ``Throwable``s implementing ``ClientRelevantError`` + will continue to be propagated to clients. * RPC Framework moved from Kryo to the Corda AMQP implementation [Corda-847]. This completes the removal of ``Kryo`` from general use within Corda, remaining only for use in flow checkpointing. diff --git a/docs/source/clientrpc.rst b/docs/source/clientrpc.rst index 7cdfc13bfe..2fce17ab7a 100644 --- a/docs/source/clientrpc.rst +++ b/docs/source/clientrpc.rst @@ -344,7 +344,8 @@ In ``devMode``, if the server implementation throws an exception, that exception side as if it was thrown from inside the called RPC method. These exceptions can be caught as normal. When not in ``devMode``, the server will mask exceptions not meant for clients and return an ``InternalNodeException`` instead. -This does not expose internal information to clients, strengthening privacy and security. CorDapps can have exceptions implement ``ClientRelevantError`` to allow them to reach RPC clients. +This does not expose internal information to clients, strengthening privacy and security. CorDapps can have exceptions implement +``ClientRelevantError`` to allow them to reach RPC clients. Connection management --------------------- diff --git a/node/src/integration-test/kotlin/net/corda/node/BootTests.kt b/node/src/integration-test/kotlin/net/corda/node/BootTests.kt index 94cafdf4f6..badb794019 100644 --- a/node/src/integration-test/kotlin/net/corda/node/BootTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/BootTests.kt @@ -12,15 +12,19 @@ import net.corda.core.messaging.startFlow import net.corda.core.utilities.getOrThrow import net.corda.node.internal.NodeStartup import net.corda.node.services.Permissions.Companion.startFlow +import net.corda.nodeapi.exceptions.InternalNodeException import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.BOB_NAME import net.corda.testing.core.DUMMY_BANK_A_NAME import net.corda.testing.driver.DriverParameters +import net.corda.testing.driver.NodeHandle +import net.corda.testing.driver.NodeParameters import net.corda.testing.driver.driver import net.corda.testing.internal.IntegrationTest import net.corda.testing.internal.IntegrationTestSchemas import net.corda.testing.internal.toDatabaseSchemaName import net.corda.testing.node.User +import net.corda.testing.node.internal.startNode import org.assertj.core.api.Assertions.assertThatThrownBy import org.junit.ClassRule import org.junit.Test @@ -38,12 +42,21 @@ class BootTests : IntegrationTest() { } @Test fun `java deserialization is disabled`() { - driver(DriverParameters(notarySpecs = emptyList())) { - val user = User("u", "p", setOf(startFlow())) - val future = CordaRPCClient(startNode(rpcUsers = listOf(user)).getOrThrow().rpcAddress). - start(user.username, user.password).proxy.startFlow(::ObjectInputStreamFlow).returnValue - assertThatThrownBy { future.getOrThrow() } - .isInstanceOf(CordaRuntimeException::class.java) + val user = User("u", "p", setOf(startFlow())) + val params = NodeParameters(rpcUsers = listOf(user)) + + fun NodeHandle.attemptJavaDeserialization() { + CordaRPCClient(rpcAddress).use(user.username, user.password) { connection -> + connection.proxy + rpc.startFlow(::ObjectInputStreamFlow).returnValue.getOrThrow() + } + } + driver { + val devModeNode = startNode(params).getOrThrow() + val node = startNode(ALICE_NAME, devMode = false, parameters = params).getOrThrow() + + assertThatThrownBy { devModeNode.attemptJavaDeserialization() }.isInstanceOf(CordaRuntimeException::class.java) + assertThatThrownBy { node.attemptJavaDeserialization() }.isInstanceOf(InternalNodeException::class.java) } } diff --git a/node/src/integration-test/kotlin/net/corda/node/services/network/NetworkMapTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/network/NetworkMapTest.kt index 6a63669bce..59db4090f8 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/network/NetworkMapTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/network/NetworkMapTest.kt @@ -247,4 +247,4 @@ class NetworkMapTest(var initFunc: (URL, NetworkMapServer) -> CompatibilityZoneP } assertThat(rpc.networkMapSnapshot()).containsOnly(*nodes) } -} \ No newline at end of file +} diff --git a/node/src/integration-test/kotlin/net/corda/node/services/rpc/RpcExceptionHandlingTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/rpc/RpcExceptionHandlingTest.kt index d8544a89c9..aa64320ef8 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/rpc/RpcExceptionHandlingTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/rpc/RpcExceptionHandlingTest.kt @@ -3,24 +3,18 @@ package net.corda.node.services.rpc import co.paralleluniverse.fibers.Suspendable import net.corda.ClientRelevantException import net.corda.core.CordaRuntimeException -import net.corda.core.flows.FlowException -import net.corda.core.flows.FlowLogic -import net.corda.core.flows.FlowSession -import net.corda.core.flows.InitiatedBy -import net.corda.core.flows.InitiatingFlow -import net.corda.core.flows.StartableByRPC +import net.corda.core.flows.* import net.corda.core.identity.Party import net.corda.core.messaging.startFlow import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.unwrap import net.corda.node.services.Permissions import net.corda.nodeapi.exceptions.InternalNodeException -import net.corda.testing.core.* -import net.corda.testing.driver.DriverDSL -import net.corda.testing.driver.DriverParameters -import net.corda.testing.driver.NodeHandle -import net.corda.testing.driver.NodeParameters -import net.corda.testing.driver.driver +import net.corda.testing.core.ALICE_NAME +import net.corda.testing.core.BOB_NAME +import net.corda.testing.core.DUMMY_NOTARY_NAME +import net.corda.testing.core.singleIdentity +import net.corda.testing.driver.* import net.corda.testing.internal.IntegrationTest import net.corda.testing.internal.IntegrationTestSchemas import net.corda.testing.internal.toDatabaseSchemaName @@ -39,7 +33,6 @@ class RpcExceptionHandlingTest : IntegrationTest() { @JvmField val databaseSchemas = IntegrationTestSchemas(ALICE_NAME.toDatabaseSchemaName(), BOB_NAME.toDatabaseSchemaName(), DUMMY_NOTARY_NAME.toDatabaseSchemaName()) } - private val user = User("mark", "dadada", setOf(Permissions.all())) private val users = listOf(user) @@ -165,4 +158,4 @@ class FlowExceptionFlow(private val message: String, private val errorId: Long? errorId?.let { exception.originalErrorId = it } throw exception } -} \ No newline at end of file +} diff --git a/node/src/main/kotlin/net/corda/node/NodeCmdLineOptions.kt b/node/src/main/kotlin/net/corda/node/NodeCmdLineOptions.kt index ab53a9c71a..426d36db91 100644 --- a/node/src/main/kotlin/net/corda/node/NodeCmdLineOptions.kt +++ b/node/src/main/kotlin/net/corda/node/NodeCmdLineOptions.kt @@ -18,7 +18,7 @@ class NodeCmdLineOptions { names = ["-b", "--base-directory"], description = ["The node working directory where all the files are kept."] ) - var baseDirectory: Path = Paths.get(".") + var baseDirectory: Path = Paths.get(".").toAbsolutePath().normalize() @Option( names = ["-f", "--config-file"], @@ -57,7 +57,7 @@ class NodeCmdLineOptions { names = ["-t", "--network-root-truststore"], description = ["Network root trust store obtained from network operator."] ) - var networkRootTrustStorePath = Paths.get("certificates") / "network-root-truststore.jks" + var networkRootTrustStorePath: Path = baseDirectory / "certificates" / "network-root-truststore.jks" @Option( names = ["-p", "--network-root-truststore-password"], diff --git a/node/src/main/kotlin/net/corda/node/internal/rpc/proxies/ExceptionMaskingRpcOpsProxy.kt b/node/src/main/kotlin/net/corda/node/internal/rpc/proxies/ExceptionMaskingRpcOpsProxy.kt index 5c6c140ef2..244fade5cb 100644 --- a/node/src/main/kotlin/net/corda/node/internal/rpc/proxies/ExceptionMaskingRpcOpsProxy.kt +++ b/node/src/main/kotlin/net/corda/node/internal/rpc/proxies/ExceptionMaskingRpcOpsProxy.kt @@ -122,4 +122,4 @@ internal class ExceptionMaskingRpcOpsProxy(private val delegate: CordaRPCOps, do override fun toString(): String { return "ExceptionMaskingRpcOpsProxy" } -} \ No newline at end of file +} diff --git a/node/src/test/kotlin/net/corda/node/NodeCmdLineOptionsTest.kt b/node/src/test/kotlin/net/corda/node/NodeCmdLineOptionsTest.kt index 1ee0e163ea..70ee537829 100644 --- a/node/src/test/kotlin/net/corda/node/NodeCmdLineOptionsTest.kt +++ b/node/src/test/kotlin/net/corda/node/NodeCmdLineOptionsTest.kt @@ -15,20 +15,18 @@ class NodeCmdLineOptionsTest { companion object { private lateinit var workingDirectory: Path - private lateinit var buildDirectory: Path @BeforeClass @JvmStatic fun initDirectories() { workingDirectory = Paths.get(".").normalize().toAbsolutePath() - buildDirectory = workingDirectory.resolve("build") } } @Test fun `no command line arguments`() { - assertThat(parser.cmdLineOptions.baseDirectory.normalize().toAbsolutePath()).isEqualTo(workingDirectory) - assertThat(parser.cmdLineOptions.configFile.normalize().toAbsolutePath()).isEqualTo(workingDirectory / "node.conf") + assertThat(parser.cmdLineOptions.baseDirectory).isEqualTo(workingDirectory) + assertThat(parser.cmdLineOptions.configFile).isEqualTo(workingDirectory / "node.conf") assertThat(parser.verbose).isEqualTo(false) assertThat(parser.loggingLevel).isEqualTo(Level.INFO) assertThat(parser.cmdLineOptions.nodeRegistrationOption).isEqualTo(null) @@ -40,5 +38,6 @@ class NodeCmdLineOptionsTest { assertThat(parser.cmdLineOptions.unknownConfigKeysPolicy).isEqualTo(UnknownConfigKeysPolicy.FAIL) assertThat(parser.cmdLineOptions.devMode).isEqualTo(null) assertThat(parser.cmdLineOptions.clearNetworkMapCache).isEqualTo(false) + assertThat(parser.cmdLineOptions.networkRootTrustStorePath).isEqualTo(workingDirectory / "certificates" / "network-root-truststore.jks") } } diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/DriverDSLImpl.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/DriverDSLImpl.kt index ee698b5c50..cb4dfe29b6 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/DriverDSLImpl.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/DriverDSLImpl.kt @@ -1190,4 +1190,4 @@ fun DriverDSL.startNode(providedName: CordaX500Name, devMode: Boolean, parameter customOverrides = mapOf("devMode" to "false") } return startNode(parameters, providedName = providedName, customOverrides = customOverrides) -} \ No newline at end of file +} diff --git a/tools/cliutils/src/main/kotlin/net/corda/cliutils/CordaCliWrapper.kt b/tools/cliutils/src/main/kotlin/net/corda/cliutils/CordaCliWrapper.kt index 8d37b5f694..f30c3ed05d 100644 --- a/tools/cliutils/src/main/kotlin/net/corda/cliutils/CordaCliWrapper.kt +++ b/tools/cliutils/src/main/kotlin/net/corda/cliutils/CordaCliWrapper.kt @@ -8,6 +8,7 @@ import org.fusesource.jansi.AnsiConsole import org.slf4j.event.Level import picocli.CommandLine import picocli.CommandLine.* +import java.nio.file.Path import java.nio.file.Paths import kotlin.system.exitProcess import java.util.* @@ -45,22 +46,24 @@ interface Validated { /** This is generally covered by commons-lang. */ object CordaSystemUtils { - const val OS_NAME = "os.name" + private const val OS_NAME = "os.name" + private const val MAC_PREFIX = "Mac" + private const val WIN_PREFIX = "Windows" - const val MAC_PREFIX = "Mac" - const val WIN_PREFIX = "Windows" - - fun isOsMac() = getOsName().startsWith(MAC_PREFIX) - fun isOsWindows() = getOsName().startsWith(WIN_PREFIX) - fun getOsName() = System.getProperty(OS_NAME) + fun isOsMac(): Boolean = getOsName().startsWith(MAC_PREFIX) + fun isOsWindows(): Boolean = getOsName().startsWith(WIN_PREFIX) + fun getOsName(): String = System.getProperty(OS_NAME) } fun CordaCliWrapper.start(args: Array) { + this.args = args + // This line makes sure ANSI escapes work on Windows, where they aren't supported out of the box. AnsiConsole.systemInstall() val cmd = CommandLine(this) - this.args = args + // Make sure any provided paths are absolute. Relative paths have caused issues and are less clear in logs. + cmd.registerConverter(Path::class.java) { Paths.get(it).toAbsolutePath().normalize() } cmd.commandSpec.name(alias) cmd.commandSpec.usageMessage().description(description) try {