From 7f2d72ee59ca0da2a2d394222b5da40f5f923c7c Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Mon, 10 Jan 2022 12:01:03 +0200 Subject: [PATCH] pass psbt and message to hwi on stdin to avoid too long process arguments --- .../com/sparrowwallet/sparrow/io/Hwi.java | 58 +++++++++++++++---- 1 file changed, 47 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/sparrowwallet/sparrow/io/Hwi.java b/src/main/java/com/sparrowwallet/sparrow/io/Hwi.java index 1dc4dcb6..7f43a8e7 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/Hwi.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/Hwi.java @@ -179,9 +179,9 @@ public class Hwi { isPromptActive = true; String output; if(passphrase != null && !passphrase.isEmpty() && device.getModel().externalPassphraseEntry()) { - output = execute(getDeviceCommand(device, passphrase, Command.SIGN_MESSAGE, message, derivationPath)); + output = execute(getDeviceArguments(device, passphrase, Command.SIGN_MESSAGE), Command.SIGN_MESSAGE, message, derivationPath); } else { - output = execute(getDeviceCommand(device, Command.SIGN_MESSAGE, message, derivationPath)); + output = execute(getDeviceArguments(device, Command.SIGN_MESSAGE), Command.SIGN_MESSAGE, message, derivationPath); } JsonObject result = JsonParser.parseString(output).getAsJsonObject(); @@ -209,9 +209,9 @@ public class Hwi { isPromptActive = true; String output; if(passphrase != null && !passphrase.isEmpty() && device.getModel().externalPassphraseEntry()) { - output = execute(getDeviceCommand(device, passphrase, Command.SIGN_TX, psbtBase64)); + output = execute(getDeviceArguments(device, passphrase, Command.SIGN_TX), Command.SIGN_TX, psbtBase64); } else { - output = execute(getDeviceCommand(device, Command.SIGN_TX, psbtBase64)); + output = execute(getDeviceArguments(device, Command.SIGN_TX), Command.SIGN_TX, psbtBase64); } JsonObject result = JsonParser.parseString(output).getAsJsonObject(); @@ -242,7 +242,31 @@ public class Hwi { private String execute(List command) throws IOException { ProcessBuilder processBuilder = new ProcessBuilder(command); Process process = processBuilder.start(); - return CharStreams.toString(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8)); + try(InputStreamReader reader = new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8)) { + return CharStreams.toString(reader); + } + } + + private String execute(List arguments, Command command, String... commandArguments) throws IOException { + List processArguments = new ArrayList<>(arguments); + processArguments.add("--stdin"); + + ProcessBuilder processBuilder = new ProcessBuilder(processArguments); + Process process = processBuilder.start(); + + try(BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream(), StandardCharsets.UTF_8))) { + writer.write(command.toString()); + for(String commandArgument : commandArguments) { + writer.write(" \""); + writer.write(commandArgument.replace("\\", "\\\\").replace("\"", "\\\"")); + writer.write("\""); + } + writer.flush(); + } + + try(InputStreamReader reader = new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8)) { + return CharStreams.toString(reader); + } } private synchronized File getHwiExecutable(Command command) { @@ -400,30 +424,42 @@ public class Hwi { return result.get("success").getAsBoolean(); } + private List getDeviceArguments(Device device, Command command) throws IOException { + List elements = new ArrayList<>(List.of(getHwiExecutable(command).getAbsolutePath(), "--device-path", device.getPath(), "--device-type", device.getType())); + addChainType(elements, false); + return elements; + } + + private List getDeviceArguments(Device device, String passphrase, Command command) throws IOException { + List elements = new ArrayList<>(List.of(getHwiExecutable(command).getAbsolutePath(), "--device-path", device.getPath(), "--device-type", device.getType(), "--password", escape(passphrase))); + addChainType(elements, false); + return elements; + } + private List getDeviceCommand(Device device, Command command) throws IOException { List elements = new ArrayList<>(List.of(getHwiExecutable(command).getAbsolutePath(), "--device-path", device.getPath(), "--device-type", device.getType(), command.toString())); - addChainType(elements); + addChainType(elements, true); return elements; } private List getDeviceCommand(Device device, Command command, String... commandData) throws IOException { List elements = new ArrayList<>(List.of(getHwiExecutable(command).getAbsolutePath(), "--device-path", device.getPath(), "--device-type", device.getType(), command.toString())); - addChainType(elements); + addChainType(elements, true); elements.addAll(Arrays.stream(commandData).filter(Objects::nonNull).collect(Collectors.toList())); return elements; } private List getDeviceCommand(Device device, String passphrase, Command command, String... commandData) throws IOException { List elements = new ArrayList<>(List.of(getHwiExecutable(command).getAbsolutePath(), "--device-path", device.getPath(), "--device-type", device.getType(), "--password", escape(passphrase), command.toString())); - addChainType(elements); + addChainType(elements, true); elements.addAll(Arrays.stream(commandData).filter(Objects::nonNull).collect(Collectors.toList())); return elements; } - private void addChainType(List elements) { + private void addChainType(List elements, boolean commandPresent) { if(Network.get() != Network.MAINNET) { - elements.add(elements.size() - 1, "--chain"); - elements.add(elements.size() - 1, getChainName(Network.get())); + elements.add(elements.size() - (commandPresent ? 1 : 0), "--chain"); + elements.add(elements.size() - (commandPresent ? 1 : 0), getChainName(Network.get())); } }