diff --git a/.gitignore b/.gitignore index 6fbce99db3..3a981cfc81 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ /log/ /rt/ /web3/ +/zmq_keystore/ /jars/ # ide diff --git a/aion_api b/aion_api index e21f8e878d..6adb12f81c 160000 --- a/aion_api +++ b/aion_api @@ -1 +1 @@ -Subproject commit e21f8e878d598724176a6d0c51fceafc85239020 +Subproject commit 6adb12f81ce775989da3acb134d4b1c3a9e146eb diff --git a/modAionBase/src/module-info.java b/modAionBase/src/module-info.java index db43d3f590..20bbee63bf 100644 --- a/modAionBase/src/module-info.java +++ b/modAionBase/src/module-info.java @@ -4,5 +4,6 @@ exports org.aion.base.util; exports org.aion.base.vm; exports org.aion.base.db; + exports org.aion.base.io; exports org.aion.base; } diff --git a/modAionBase/src/org/aion/base/io/File.java b/modAionBase/src/org/aion/base/io/File.java new file mode 100644 index 0000000000..fabfeaf005 --- /dev/null +++ b/modAionBase/src/org/aion/base/io/File.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2017-2018 Aion foundation. + * + * This file is part of the aion network project. + * + * The aion network project is free software: you can redistribute it + * and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or any later version. + * + * The aion network project is distributed in the hope that it will + * be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the aion network project source files. + * If not, see . + * + * Contributors: + * Aion foundation. + */ + +package org.aion.base.io; + +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class File { + public static List getFiles(final Path path) { + if (path == null) { + System.out.println("getFiles null path input!"); + return Collections.emptyList(); + } + + try { + java.io.File[] files = path.toFile().listFiles(); + return files != null ? Arrays.asList(files) : Collections.emptyList(); + } catch (UnsupportedOperationException | NullPointerException e) { + System.out.println("getFiles exception: " + e.toString()); + return Collections.emptyList(); + } + } +} diff --git a/modAionImpl/build.xml b/modAionImpl/build.xml index 1867a6d295..ad3ff92512 100644 --- a/modAionImpl/build.xml +++ b/modAionImpl/build.xml @@ -172,6 +172,8 @@ + + diff --git a/modAionImpl/src/module-info.java b/modAionImpl/src/module-info.java index d59cc69e97..0fa7b4df30 100644 --- a/modAionImpl/src/module-info.java +++ b/modAionImpl/src/module-info.java @@ -1,4 +1,6 @@ module aion.zero.impl { + uses org.aion.evtmgr.EventMgrModule; + uses org.aion.txpool.TxPoolModule; requires aion.base; requires aion.mcf; requires aion.log; @@ -17,6 +19,9 @@ requires jdk.management; requires java.xml; requires slf4j.api; + requires com.google.common; + requires info.picocli; + requires commons.lang3; exports org.aion.equihash; exports org.aion.zero.impl.blockchain; @@ -25,6 +30,7 @@ exports org.aion.zero.impl.types; exports org.aion.zero.impl.config; exports org.aion.zero.impl.cli; + opens org.aion.zero.impl.cli; exports org.aion.zero.impl.db; exports org.aion.zero.impl.sync; exports org.aion.zero.impl.config.dynamic; diff --git a/modApiServer/src/org/aion/api/server/ApiAion.java b/modApiServer/src/org/aion/api/server/ApiAion.java index bcbece4e8b..d413feaefc 100644 --- a/modApiServer/src/org/aion/api/server/ApiAion.java +++ b/modApiServer/src/org/aion/api/server/ApiAion.java @@ -80,7 +80,7 @@ public abstract class ApiAion extends Api { // 2. underlying datastructure provides concurrency guarntees // delegate concurrency to underlying object - protected static NrgOracle NRG_ORACLE; + private static NrgOracle NRG_ORACLE; protected IAionChain ac; // assumption: blockchainImpl et al. provide concurrency guarantee // using java.util.concurrent library objects @@ -224,7 +224,7 @@ public AionBlock getBlock(long blkNr) { } } - public Map.Entry getBlockWithTotalDifficulty(long blkNr) { + protected Map.Entry getBlockWithTotalDifficulty(long blkNr) { if (blkNr > 0) { return ((AionBlockStore) this.ac.getBlockchain().getBlockStore()) .getChainBlockByNumberWithTotalDifficulty(blkNr); diff --git a/modApiServer/src/org/aion/api/server/zmq/HdlrZmq.java b/modApiServer/src/org/aion/api/server/zmq/HdlrZmq.java index 5a7de9acdf..7e5da4b64c 100644 --- a/modApiServer/src/org/aion/api/server/zmq/HdlrZmq.java +++ b/modApiServer/src/org/aion/api/server/zmq/HdlrZmq.java @@ -1,4 +1,4 @@ -/******************************************************************************* +/* * Copyright (c) 2017-2018 Aion foundation. * * This file is part of the aion network project. @@ -19,8 +19,7 @@ * * Contributors: * Aion foundation. - * - ******************************************************************************/ + */ package org.aion.api.server.zmq; @@ -70,7 +69,7 @@ public byte[] process(byte[] request, byte[] socketId) { } } - public void getTxWait() { + void getTxWait() { TxWaitingMappingUpdate txWait = null; try { txWait = this.api.takeTxWait(); @@ -107,15 +106,15 @@ public Map getFilter() { return this.api.getFilter(); } - public BlockingQueue getTxStatusQueue() { + BlockingQueue getTxStatusQueue() { return this.api.getPendingStatus(); } - public byte[] toRspMsg(byte[] msgHash, int txCode, String error) { + byte[] toRspMsg(byte[] msgHash, int txCode, String error) { return ApiUtil.toReturnHeader(this.api.getApiVersion(), txCode, msgHash, error.getBytes()); } - public byte[] toRspMsg(byte[] msgHash, int txCode, String error, byte[] result) { + byte[] toRspMsg(byte[] msgHash, int txCode, String error, byte[] result) { return ApiUtil.toReturnHeader(this.api.getApiVersion(), txCode, msgHash, error.getBytes(), result); } @@ -124,7 +123,7 @@ public byte[] process(byte[] request) { return null; } - public byte[] toRspEvtMsg(byte[] ecb) { + byte[] toRspEvtMsg(byte[] ecb) { return ApiUtil.toReturnEvtHeader(this.api.getApiVersion(), ecb); } diff --git a/modApiServer/src/org/aion/api/server/zmq/ProtocolProcessor.java b/modApiServer/src/org/aion/api/server/zmq/ProtocolProcessor.java index ff0338b7bf..50def756a7 100644 --- a/modApiServer/src/org/aion/api/server/zmq/ProtocolProcessor.java +++ b/modApiServer/src/org/aion/api/server/zmq/ProtocolProcessor.java @@ -27,7 +27,12 @@ import static org.zeromq.ZMQ.DEALER; import static org.zeromq.ZMQ.ROUTER; +import java.io.File; +import java.io.IOException; import java.nio.ByteBuffer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -53,22 +58,32 @@ public class ProtocolProcessor implements Runnable { protected static final Logger LOG = AionLoggerFactory.getLogger(LogEnum.API.name()); - private final IHdlr handler; private static final String AION_ZMQ_WK_TH = "inproc://aionZmqWkTh"; private static final String AION_ZMQ_CB_TH = "inproc://aionZmqCbTh"; private static final String AION_ZMQ_EV_TH = "inproc://aionZmqEvTh"; private static final String AION_ZMQ_HB_TH = "inproc://aionZmqHbTh"; - - private CfgApiZmq cfgApi; - private AtomicBoolean shutDown = new AtomicBoolean(); - + private final Path PATH; private static final long zmqHWM = 100_000; private static final int SOCKETID_LEN = 5; private static final int SOCKET_RECV_TIMEOUT = 3000; + private final IHdlr handler; + private CfgApiZmq cfgApi; + private AtomicBoolean shutDown = new AtomicBoolean(); + private byte[] curvePubKey; + private byte[] curveSecKey; + public ProtocolProcessor(IHdlr _handler, final CfgApiZmq cfg) { this.handler = _handler; this.cfgApi = cfg; + + String storageDir = System.getProperty("local.storage.dir"); + if (storageDir == null || storageDir.equalsIgnoreCase("")) { + storageDir = System.getProperty("user.dir"); + } + + String curveKeyPath = storageDir + "/" + CfgApiZmq.ZMQ_KEY_DIR; + PATH = Paths.get(curveKeyPath); } public void shutdown() throws InterruptedException { @@ -90,6 +105,23 @@ public void run() { // create router sock. Socket feSock = ctx.socket(ROUTER); + if (cfgApi.isSecureConnectEnabledEnabled()) { + // Currently the system will only load the first pair of the key files. + loadCurveKeyPair(); + + if (curveSecKey != null && curvePubKey != null) { + feSock.setZAPDomain("global".getBytes()); + feSock.setCurveServer(true); + feSock.setCurvePublicKey(curvePubKey); + feSock.setCurveSecretKey(curveSecKey); + LOG.info("Secure connection enabled!"); + } else { + LOG.info("Can't find the keyfile for setup the connection. Secure connection disabled!"); + } + } else { + LOG.info("Secure connection disabled!"); + } + feSock.setSndHWM(zmqHWM); feSock.bind(bindAddr); @@ -144,6 +176,39 @@ public void run() { } } + private void loadCurveKeyPair() { + List files = org.aion.base.io.File.getFiles(PATH); + String nextLoad = ""; + for (File f : files) { + if (f.getName().contains("zmqCurvePubkey")) { + try { + curvePubKey = Files.readAllBytes(f.toPath()); + nextLoad = f.getName().replace("zmqCurvePubkey", "zmqCurveSeckey"); + } catch (IOException e) { + LOG.error("Get zmqCurvePubkey exception! {}", e.toString()); + } + } else if (f.getName().contains("zmqCurveSeckey")) { + try { + curveSecKey = Files.readAllBytes(f.toPath()); + nextLoad = f.getName().replace("zmqCurveSeckey", "zmqCurvePubkey"); + } catch (IOException e) { + LOG.error("Get zmqCurveSeckey exception! {}", e.toString()); + } + } else if (nextLoad.contentEquals(f.getName())){ + try { + if (nextLoad.contains("zmqCurveSeckey")) { + curveSecKey = Files.readAllBytes(f.toPath()); + } else { + curvePubKey = Files.readAllBytes(f.toPath()); + } + } catch (IOException e) { + LOG.error("Get zmqCurveSeckey exception! {}", e.toString()); + } + break; + } + } + } + private void eventRun(Context ctx) { Socket sock = ctx.socket(ZMQ.DEALER); sock.connect(AION_ZMQ_EV_TH); @@ -168,15 +233,18 @@ private void eventRun(Context ctx) { } if (!al.isEmpty()) { - Message.rsp_EventCtCallback ecb = Message.rsp_EventCtCallback.newBuilder().addAllEc(al).build(); + Message.rsp_EventCtCallback ecb = Message.rsp_EventCtCallback.newBuilder() + .addAllEc(al).build(); byte[] rsp = ((HdlrZmq) this.handler).toRspEvtMsg(ecb.toByteArray()); try { - byte[] socketId = ByteBuffer.allocate(5).put(ByteUtil.longToBytes(i), 3, 5).array(); + byte[] socketId = ByteBuffer.allocate(5) + .put(ByteUtil.longToBytes(i), 3, 5).array(); sock.send(socketId, ZMQ.SNDMORE); sock.send(rsp, ZMQ.DONTWAIT); } catch (Exception e) { - LOG.error("ProtocolProcessor.callbackRun sock.send exception: " + e.getMessage()); + LOG.error("ProtocolProcessor.callbackRun sock.send exception: " + e + .getMessage()); } } } @@ -220,19 +288,25 @@ private void callbackRun(Context ctx) { } byte[] rsp = tps.toTxReturnCode() != 105 - ? ((HdlrZmq) this.handler).toRspMsg(tps.getMsgHash(), tps.toTxReturnCode(), tps.getError()) - : ((HdlrZmq) this.handler).toRspMsg(tps.getMsgHash(), tps.toTxReturnCode(), tps.getError(), tps.getTxResult()); + ? ((HdlrZmq) this.handler) + .toRspMsg(tps.getMsgHash(), tps.toTxReturnCode(), tps.getError()) + : ((HdlrZmq) this.handler) + .toRspMsg(tps.getMsgHash(), tps.toTxReturnCode(), tps.getError(), + tps.getTxResult()); if (LOG.isTraceEnabled()) { - LOG.trace("callbackRun send. socketID: [{}], msgHash: [{}], txReturnCode: [{}]/n rspMsg: [{}]", - Hex.toHexString(tps.getSocketId()), Hex.toHexString(tps.getMsgHash()), tps.toTxReturnCode(), - Hex.toHexString(rsp)); + LOG.trace( + "callbackRun send. socketID: [{}], msgHash: [{}], txReturnCode: [{}]/n rspMsg: [{}]", + Hex.toHexString(tps.getSocketId()), Hex.toHexString(tps.getMsgHash()), + tps.toTxReturnCode(), + Hex.toHexString(rsp)); } try { sock.send(tps.getSocketId(), ZMQ.SNDMORE); sock.send(rsp, ZMQ.DONTWAIT); } catch (Exception e) { if (LOG.isErrorEnabled()) { - LOG.error("ProtocolProcessor.callbackRun sock.send exception: " + e.getMessage()); + LOG.error( + "ProtocolProcessor.callbackRun sock.send exception: " + e.getMessage()); } } } @@ -251,7 +325,8 @@ private void workerRun(ZMQ.Context ctx) { try { byte[] socketId = sock.recv(0); if (LOG.isTraceEnabled()) { - LOG.trace("ProtocolProcessor.workerRun socketID: [{}]", Hex.toHexString(socketId)); + LOG.trace("ProtocolProcessor.workerRun socketID: [{}]", + Hex.toHexString(socketId)); } if (socketId != null && socketId.length == SOCKETID_LEN) { byte[] req = sock.recv(0); diff --git a/modBoot/resource/custom/config.xml b/modBoot/resource/custom/config.xml index 645f43f1ec..46885fbb6d 100644 --- a/modBoot/resource/custom/config.xml +++ b/modBoot/resource/custom/config.xml @@ -11,7 +11,9 @@ 1 - + + true + 10E9 diff --git a/modBoot/resource/mainnet/config.xml b/modBoot/resource/mainnet/config.xml index bedb9e6e89..60d31003eb 100644 --- a/modBoot/resource/mainnet/config.xml +++ b/modBoot/resource/mainnet/config.xml @@ -4,12 +4,15 @@ [NODE-ID-PLACEHOLDER] - + false web3,eth,personal,stratum,ops - + + true + + 10E9 diff --git a/modBoot/resource/mastery/config.xml b/modBoot/resource/mastery/config.xml index 1f1ec44ce6..20e59bc45e 100755 --- a/modBoot/resource/mastery/config.xml +++ b/modBoot/resource/mastery/config.xml @@ -9,7 +9,9 @@ web3,eth,personal,stratum,ops - + + true + 10E9 diff --git a/modBoot/src/module-info.java b/modBoot/src/module-info.java index fb01f68383..d0fd73da79 100644 --- a/modBoot/src/module-info.java +++ b/modBoot/src/module-info.java @@ -1,4 +1,6 @@ module aion.boot { + uses org.aion.evtmgr.EventMgrModule; + uses org.aion.log.AionLoggerFactory; requires aion.crypto; requires aion.apiserver; @@ -9,8 +11,8 @@ requires slf4j.api; requires aion.p2p; requires aion.fastvm; - - + requires aion.base; + requires libnzmq; exports org.aion; } diff --git a/modBoot/src/org/aion/Aion.java b/modBoot/src/org/aion/Aion.java index 7281620beb..5f6b2baa79 100644 --- a/modBoot/src/org/aion/Aion.java +++ b/modBoot/src/org/aion/Aion.java @@ -30,8 +30,17 @@ import static org.aion.zero.impl.cli.Cli.ReturnType; import java.io.Console; +import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; -import java.util.ServiceLoader; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.attribute.FileAttribute; +import java.nio.file.attribute.PosixFilePermission; +import java.nio.file.attribute.PosixFilePermissions; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.*; import java.util.function.Consumer; import org.aion.api.server.http.RpcServer; import org.aion.api.server.http.RpcServerBuilder; @@ -49,6 +58,7 @@ import org.aion.log.LogEnum; import org.aion.mcf.account.Keystore; import org.aion.mcf.config.CfgApiRpc; +import org.aion.mcf.config.CfgApiZmq; import org.aion.mcf.config.CfgSsl; import org.aion.mcf.mine.IMineRunner; import org.aion.solidity.Compiler; @@ -59,6 +69,7 @@ import org.aion.zero.impl.config.CfgAion; import org.aion.zero.impl.config.Network; import org.slf4j.Logger; +import org.zeromq.ZMQ; public class Aion { @@ -88,11 +99,22 @@ public static void main(String args[]) { exit(ret.getValue()); } + //Check ZMQ server secure connect settings, generate keypair when the settings enabled and can't find the keypair. + if (cfg.getApi().getZmq().getActive() && cfg.getApi().getZmq() + .isSecureConnectEnabledEnabled()) { + try { + checkZmqKeyPair(); + } catch (Exception e) { + System.out.println("Check zmq keypair fail! " + e.toString()); + exit(1); + } + } + // UUID check String UUID = cfg.getId(); if (!UUID.matches("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}")) { System.out.println("Invalid UUID; please check setting in config.xml"); - exit(-1); + exit(1); } ServiceLoader.load(EventMgrModule.class); @@ -138,7 +160,7 @@ public static void main(String args[]) { filePath[6] = cfg.getInitialGenesisFile().getAbsolutePath(); String path = - "\n-------------------------------- USED PATHS --------------------------------" + + "\n-------------------------------- USED PATHS --------------------------------" + "\n> Logger path: " + filePath[0] + "\n> Database path: " + filePath[1] + "\n> Keystore path: " + filePath[2] + @@ -150,7 +172,7 @@ public static void main(String args[]) { "\n----------------------------------------------------------------------------\n\n"; String logo = - "\n _____ \n" + + "\n _____ \n" + " .'. | .~ ~. |.. |\n" + " .' `. | | | | ``.. |\n" + " .''''''''`. | | | | ``.. |\n" + @@ -163,6 +185,7 @@ public static void main(String args[]) { if (networkStr == null && cfg.getNet().getId() >= 0) { networkStr = Network.determineNetwork(cfg.getNet().getId()).toString(); } + logo = appendLogo(logo, versionStr); if (networkStr != null) { logo = appendLogo(logo, networkStr); @@ -216,8 +239,8 @@ public static void main(String args[]) { } RpcServer rpcServer = null; - if(cfg.getApi().getRpc().isActive()) { - CfgApiRpc rpcCfg = cfg.getApi().getRpc(); + if (cfg.getApi().getRpc().isActive()) { + CfgApiRpc rpcCfg = cfg.getApi().getRpc(); Consumer>> commonRpcConfig = (rpcBuilder) -> { rpcBuilder.setUrl(rpcCfg.getIp(), rpcCfg.getPort()); @@ -230,14 +253,17 @@ public static void main(String args[]) { rpcBuilder.setRequestQueueSize(rpcCfg.getRequestQueueSize()); rpcBuilder.setStuckThreadDetectorEnabled(rpcCfg.isStuckThreadDetectorEnabled()); - if (rpcCfg.isCorsEnabled()) + if (rpcCfg.isCorsEnabled()) { rpcBuilder.enableCorsWithOrigin(rpcCfg.getCorsOrigin()); + } CfgSsl cfgSsl = rpcCfg.getSsl(); - if (cfgSsl.getEnabled()) + if (cfgSsl.getEnabled()) { rpcBuilder.enableSsl(cfgSsl.getCert(), sslPass); + } }; - RpcServerVendor rpcVendor = RpcServerVendor.fromString(rpcCfg.getVendor()).orElse(RpcServerVendor.UNDERTOW); + RpcServerVendor rpcVendor = RpcServerVendor.fromString(rpcCfg.getVendor()) + .orElse(RpcServerVendor.UNDERTOW); try { switch (rpcVendor) { case NANO: { @@ -258,9 +284,11 @@ public static void main(String args[]) { genLog.error("Failed to instantiate RPC server.", e); } - if (rpcServer == null) - throw new IllegalStateException("Issue with RPC settings caused server instantiation to fail. " + + if (rpcServer == null) { + throw new IllegalStateException( + "Issue with RPC settings caused server instantiation to fail. " + "Please check RPC settings in config file."); + } rpcServer.start(); } @@ -276,7 +304,8 @@ class ShutdownThreadHolder { private final ProtocolProcessor pp; private final RpcServer rpc; - private ShutdownThreadHolder(Thread zmqThread, IMineRunner nm, ProtocolProcessor pp, RpcServer rpc) { + private ShutdownThreadHolder(Thread zmqThread, IMineRunner nm, ProtocolProcessor pp, + RpcServer rpc) { this.zmqThread = zmqThread; this.miner = nm; this.pp = pp; @@ -336,10 +365,78 @@ private ShutdownThreadHolder(Thread zmqThread, IMineRunner nm, ProtocolProcessor } - public static String appendLogo(String value, String input) { + private static void checkZmqKeyPair() throws IOException { + File zmqkeyDir = new File( + System.getProperty("user.dir") + File.separator + CfgApiZmq.ZMQ_KEY_DIR); + + if (!zmqkeyDir.isDirectory()) { + if (!zmqkeyDir.mkdir()) { + System.out.println("zmq keystore directory could not be created. " + + "Please check user permissions or create directory manually."); + System.exit(1); + } + System.out.println(); + } + + if (!existZmqSecKeyFile(zmqkeyDir.toPath())) { + System.out.print("Can't find zmq key pair, generate new pair! \n"); + ZMQ.Curve.KeyPair kp = ZMQ.Curve.generateKeyPair(); + genKeyFile(zmqkeyDir.getPath(), kp.publicKey, kp.secretKey); + } else { + System.out.print("Find zmq key pair! \n"); + } + + } + + private static boolean existZmqSecKeyFile(final Path path) { + List files = org.aion.base.io.File.getFiles(path); + + for (File file : files) { + if (file.getName().contains("zmqCurveSeckey")) { + return true; + } + } + + return false; + } + + private static void genKeyFile(final String path, final String publicKey, + final String secretKey) throws IOException { + DateFormat df = new SimpleDateFormat("yy-MM-dd'T'HH-mm-ss'Z'"); + df.setTimeZone(TimeZone.getTimeZone("UTC")); + String iso_date = df.format(new Date(System.currentTimeMillis())); + + String fileName = "UTC--" + iso_date + "--zmqCurvePubkey"; + writeKeyToFile(path, fileName, publicKey); + + fileName = "UTC--" + iso_date + "--zmqCurveSeckey"; + writeKeyToFile(path, fileName, secretKey); + } + + private static void writeKeyToFile(final String path, final String fileName, final String key) + throws IOException { + Set perms = PosixFilePermissions.fromString("rwxr-----"); + FileAttribute> attr = PosixFilePermissions.asFileAttribute(perms); + + Path p = Paths.get(path).resolve(fileName); + Path keyFile; + if (!java.nio.file.Files.exists(p)) { + keyFile = java.nio.file.Files.createFile(p, attr); + } else { + keyFile = p; + } + + FileOutputStream fos = new FileOutputStream(keyFile.toString()); + fos.write(key.getBytes()); + fos.close(); + } + + private static String appendLogo(String value, String input) { int leftPad = Math.round((44 - input.length()) / 2.0f) + 1; StringBuilder padInput = new StringBuilder(); - for (int i = 0; i < leftPad; i++) padInput.append(" "); + for (int i = 0; i < leftPad; i++) { + padInput.append(" "); + } padInput.append(input); value += padInput.toString(); value += "\n\n"; @@ -358,7 +455,8 @@ private static char[] getSslPassword(CfgAion cfg) { // 2) process started in non-interactive mode (background scheduler, redirected output, etc.) // don't wan't to compromise security in these scenarios if (console == null) { - System.out.println("SSL-certificate-use requested with RPC server and no console found. " + + System.out.println( + "SSL-certificate-use requested with RPC server and no console found. " + "Please set the ssl password in the config file (insecure) to run kernel non-interactively with this option."); exit(1); } else { @@ -366,7 +464,7 @@ private static char[] getSslPassword(CfgAion cfg) { console.printf("----------- INTERACTION REQUIRED ------------\n"); console.printf("---------------------------------------------\n"); sslPass = console.readPassword("Password for SSL keystore file [" - +sslCfg.getCert()+"]\n"); + + sslCfg.getCert() + "]\n"); } } diff --git a/modCrypto/src/module-info.java b/modCrypto/src/module-info.java index 8d38edb738..1c8388def6 100644 --- a/modCrypto/src/module-info.java +++ b/modCrypto/src/module-info.java @@ -2,6 +2,7 @@ requires slf4j.api; requires aion.base; requires aion.rlp; + requires libnsc; exports org.aion.crypto; exports org.aion.crypto.hash; exports org.aion.crypto.ed25519; diff --git a/modMcf/src/module-info.java b/modMcf/src/module-info.java index d902a5bd56..8c0589c0fe 100644 --- a/modMcf/src/module-info.java +++ b/modMcf/src/module-info.java @@ -7,6 +7,7 @@ requires aion.db.impl; requires slf4j.api; requires aion.p2p; + requires com.google.common; exports org.aion.mcf.account; exports org.aion.mcf.blockchain; diff --git a/modMcf/src/org/aion/mcf/account/Keystore.java b/modMcf/src/org/aion/mcf/account/Keystore.java index b2b572888f..7d1013db8d 100644 --- a/modMcf/src/org/aion/mcf/account/Keystore.java +++ b/modMcf/src/org/aion/mcf/account/Keystore.java @@ -1,5 +1,4 @@ /* - ****************************************************************************** * Copyright (c) 2017-2018 Aion foundation. * * This file is part of the aion network project. @@ -18,12 +17,6 @@ * along with the aion network project source files. * If not, see . * - * The aion network project leverages useful source code from other - * open source projects. We greatly appreciate the effort that was - * invested in these projects and we thank the individual contributors - * for their work. For provenance information and contributors - * please see . - * * Contributors to the aion source files in decreasing order of code volume: * Aion foundation. * team through the ethereumJ library. @@ -32,8 +25,9 @@ * Samuel Neves through the BLAKE2 implementation. * Zcash project team. * Bitcoinj team. - ***************************************************************************** */ + + package org.aion.mcf.account; import java.io.File; @@ -48,8 +42,6 @@ import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -92,11 +84,6 @@ public class Keystore { PATH = Paths.get(KEYSTORE_PATH); } - private static List getFiles() { - File[] files = PATH.toFile().listFiles(); - return files != null ? Arrays.asList(files) : Collections.emptyList(); - } - public static String create(String password) { return create(password, ECKeyFac.inst().create()); } @@ -160,7 +147,7 @@ public static Map backupAccount(Map throw new NullPointerException(); } - List files = getFiles(); + List files = org.aion.base.io.File.getFiles(PATH); if (files == null) { if (LOG.isWarnEnabled()) { LOG.warn("No key file been stored in the kernel."); @@ -213,7 +200,7 @@ public static Map backupAccount(Map } public static String[] list() { - return addAddrs(getFiles()).toArray(new String[0]); + return addAddrs(org.aion.base.io.File.getFiles(PATH)).toArray(new String[0]); } private static List addAddrs(List files) { @@ -240,7 +227,7 @@ private static List addAddrs(List files) { * @return address represent by String as a List */ public static List accountsSorted() { - List files = getFiles(); + List files = org.aion.base.io.File.getFiles(PATH); files.sort(COMPARE); return addAddrs(files); } @@ -252,7 +239,7 @@ public static ECKey getKey(String _address, String _password) { ECKey key = null; if (_address.startsWith(AION_PREFIX)) { - List files = getFiles(); + List files = org.aion.base.io.File.getFiles(PATH); for (File file : files) { if (HEX_64.matcher(_address).find() && file.getName().contains(_address)) { try { @@ -282,7 +269,7 @@ public static boolean exist(String _address) { boolean flag = false; if (_address.startsWith(AION_PREFIX)) { - List files = getFiles(); + List files = org.aion.base.io.File.getFiles(PATH); for (File file : files) { if (HEX_64.matcher(_address).find() && file.getName().contains(_address)) { flag = true; @@ -338,7 +325,7 @@ public static Set importAccount(Map importKey) { * Test method. Don't use it for the code dev. */ static File getAccountFile(String address, String password) { - List files = getFiles(); + List files = org.aion.base.io.File.getFiles(PATH); if (files == null) { if (LOG.isWarnEnabled()) { LOG.warn("No key file been stored in the kernel."); diff --git a/modMcf/src/org/aion/mcf/config/CfgApiZmq.java b/modMcf/src/org/aion/mcf/config/CfgApiZmq.java index b86bdfe93c..74520ef5ca 100644 --- a/modMcf/src/org/aion/mcf/config/CfgApiZmq.java +++ b/modMcf/src/org/aion/mcf/config/CfgApiZmq.java @@ -1,11 +1,11 @@ -/******************************************************************************* +/* * Copyright (c) 2017-2018 Aion foundation. * * This file is part of the aion network project. * * The aion network project is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of + * as published by the Free Software Foundation, either versio 3 of * the License, or any later version. * * The aion network project is distributed in the hope that it will @@ -19,38 +19,41 @@ * * Contributors: * Aion foundation. - * - ******************************************************************************/ + */ package org.aion.mcf.config; import com.google.common.base.Objects; - +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamWriter; -import java.io.IOException; -import java.io.StringWriter; -import java.io.Writer; -import java.util.ArrayList; -import java.util.stream.Collectors; -import java.util.stream.Stream; +import org.aion.log.AionLoggerFactory; +import org.slf4j.Logger; public class CfgApiZmq { + public static final String ZMQ_KEY_DIR = "zmq_keystore"; + CfgApiZmq() { this.active = true; this.ip = "127.0.0.1"; this.port = 8547; this.filtersEnabled = true; this.blockSummaryCacheEnabled = false; + this.secureConnectEnabled = false; } protected boolean active; protected String ip; protected int port; - protected boolean filtersEnabled; - protected boolean blockSummaryCacheEnabled; + private boolean filtersEnabled; + private boolean blockSummaryCacheEnabled; + private boolean secureConnectEnabled; + + private static Logger LOG_GEN = AionLoggerFactory.getLogger("GEN"); public void fromXML(final XMLStreamReader sr) throws XMLStreamException { this.active = Boolean.parseBoolean(sr.getAttributeValue(null, "active")); @@ -69,16 +72,22 @@ public void fromXML(final XMLStreamReader sr) throws XMLStreamException { try { filtersEnabled = Boolean.parseBoolean(Cfg.readValue(sr)); } catch (Exception e) { - //System.out.println("failed to read config node: aion.api.rpc.filters-enabled; using preset: " + this.filtersEnabled); - //e.printStackTrace(); + LOG_GEN.warn("failed to read config node: aion.api.zmq.filters-enabled; using preset: {}\n {}" + this.filtersEnabled, e); + e.printStackTrace(); } break; case "block-summary-cache": try { blockSummaryCacheEnabled = Boolean.parseBoolean(Cfg.readValue(sr)); } catch (Exception e) { - //System.out.println("failed to read config node: aion.api.rpc.filters-enabled; using preset: " + this.filtersEnabled); - //e.printStackTrace(); + LOG_GEN.warn("failed to read config node: aion.api.zmq.block-summary-cache; using preset: {}\n {}", this.blockSummaryCacheEnabled, e); + } + break; + case "secure-connect": + try { + secureConnectEnabled = Boolean.parseBoolean(Cfg.readValue(sr)); + } catch (Exception e) { + LOG_GEN.warn("failed to read config node: aion.api.zmq.secure-connect; using preset: {}\n {}" + this.secureConnectEnabled, e); } break; default: @@ -111,6 +120,12 @@ String toXML() { xmlWriter.writeAttribute("ip", this.ip); xmlWriter.writeAttribute("port", this.port + ""); + xmlWriter.writeCharacters("\r\n\t\t\t"); + xmlWriter.writeStartElement("secure-connect"); + xmlWriter.writeCharacters(String.valueOf(this.secureConnectEnabled)); + xmlWriter.writeEndElement(); + + xmlWriter.writeCharacters("\r\n\t\t"); xmlWriter.writeEndElement(); xml = strWriter.toString(); strWriter.flush(); @@ -135,6 +150,8 @@ public int getPort() { } public boolean isFiltersEnabled() { return this.filtersEnabled; } public boolean isBlockSummaryCacheEnabled() { return this.blockSummaryCacheEnabled; } + public boolean isSecureConnectEnabledEnabled() { return this.secureConnectEnabled; } + @Override public boolean equals(Object o) { @@ -145,11 +162,12 @@ public boolean equals(Object o) { port == cfgApiZmq.port && filtersEnabled == cfgApiZmq.filtersEnabled && blockSummaryCacheEnabled == cfgApiZmq.blockSummaryCacheEnabled && + secureConnectEnabled == cfgApiZmq.secureConnectEnabled && Objects.equal(ip, cfgApiZmq.ip); } @Override public int hashCode() { - return Objects.hashCode(active, ip, port, filtersEnabled, blockSummaryCacheEnabled); + return Objects.hashCode(active, ip, port, filtersEnabled, blockSummaryCacheEnabled, secureConnectEnabled); } }