diff --git a/.gitignore b/.gitignore index 5def27e..d96080a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +__tinyencrypt_config.json out/ build classes diff --git a/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptArgs.java b/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptArgs.java index bae65fd..d6b9306 100644 --- a/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptArgs.java +++ b/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptArgs.java @@ -49,6 +49,9 @@ public class TinyEncryptArgs { @CommandLine.Option(names = {"--init-config"}, description = "Init encrypt config") boolean doInitConfig = false; + @CommandLine.Option(names = {"--encrypt-config-local-private-key"}, description = "Do encrypt config local private key") + boolean doEncryptConfigLocalPrivateKey = false; + @CommandLine.Option(names = {"-h", "--help"}, usageHelp = true, description = "Display a help message") boolean helpRequested = false; diff --git a/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptArgsUtil.java b/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptArgsUtil.java new file mode 100644 index 0000000..1dbac23 --- /dev/null +++ b/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptArgsUtil.java @@ -0,0 +1,32 @@ +package me.hatter.tools.tinyencrypt; + +import me.hatter.tools.commons.io.RFile; +import picocli.CommandLine; + +public class TinyEncryptArgsUtil { + private static final String DEFAULT_TINY_ENCRYPT_CONFIG = "~/.tinyencrypt_config.json"; + + + public static TinyEncryptArgs parseTinyEncryptArgs(String[] args) { + TinyEncryptArgs tinyEncryptArgs = new TinyEncryptArgs(); + CommandLine cmd = new CommandLine(tinyEncryptArgs); + cmd.parseArgs(args); + + if (cmd.isUsageHelpRequested()) { + cmd.usage(cmd.getOut()); + return null; + } else if (cmd.isVersionHelpRequested()) { + cmd.printVersionHelp(cmd.getOut()); + return null; + } + return tinyEncryptArgs; + } + + public static RFile getTinyEncryptConfigRFile(TinyEncryptArgs tinyEncryptArgs) { + if (tinyEncryptArgs.config != null) { + return RFile.from(tinyEncryptArgs.config); + } else { + return RFile.from(DEFAULT_TINY_ENCRYPT_CONFIG); + } + } +} diff --git a/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptMain.java b/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptMain.java index 537b929..981560a 100644 --- a/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptMain.java +++ b/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptMain.java @@ -9,10 +9,13 @@ import me.hatter.tools.commons.log.LogConfig; import me.hatter.tools.commons.log.LogTool; import me.hatter.tools.commons.log.LogTools; import me.hatter.tools.commons.security.bc.BCUtil; +import me.hatter.tools.commons.security.crypt.AESCryptTool; import me.hatter.tools.commons.security.digest.Digests; import me.hatter.tools.commons.security.key.KeyPairTool; import me.hatter.tools.commons.security.key.KeyUtil; import me.hatter.tools.commons.security.key.PKType; +import me.hatter.tools.commons.security.random.RandomTool; +import me.hatter.tools.commons.string.JSONUtil; import me.hatter.tools.commons.string.StringUtil; import me.hatter.tools.commons.tlv.Tlv; import me.hatter.tools.commons.tlv.TlvUtil; @@ -20,15 +23,15 @@ import me.hatter.tools.tinyencrypt.config.TinyEncryptConfig; import me.hatter.tools.tinyencrypt.config.TinyEncryptConstant; import me.hatter.tools.tinyencrypt.encrypt.EncryptedFileUtil; import me.hatter.tools.tinyencrypt.encrypt.TinyEncryptMeta; -import picocli.CommandLine; +import me.hatter.tools.tinyencrypt.util.CardCliUtil; import java.io.File; import java.io.FileInputStream; import java.security.KeyPair; import java.util.Date; +import java.util.Optional; public class TinyEncryptMain { - private static final String DEFAULT_TINY_ENCRYPT_CONFIG = "~/.tinyencrypt_config.json"; private static final LogTool log; static { @@ -36,19 +39,34 @@ public class TinyEncryptMain { log = LogTools.getLogTool(TinyEncryptMain.class); } - private static TinyEncryptArgs parseTinyEncryptArgs(String[] args) { - TinyEncryptArgs tinyEncryptArgs = new TinyEncryptArgs(); - CommandLine cmd = new CommandLine(tinyEncryptArgs); - cmd.parseArgs(args); - - if (cmd.isUsageHelpRequested()) { - cmd.usage(cmd.getOut()); - return null; - } else if (cmd.isVersionHelpRequested()) { - cmd.printVersionHelp(cmd.getOut()); - return null; + private static void doEncryptConfigLocalPrivateKey(TinyEncryptArgs tinyEncryptArgs) { + TinyEncryptConfig config = TinyEncryptMainUtil.loadTinyEncryptConfig(tinyEncryptArgs); + if (config == null) { + return; } - return tinyEncryptArgs; + if (StringUtil.isEmpty(config.getLocalPrivateKeyPem())) { + log.error("Local private key pem is empty!"); + return; + } + if (StringUtil.isNotEmpty(config.getLocalPrivateKeyPemEncrypted()) + || StringUtil.isNotEmpty(config.getLocalPrivateKeyPemChallenge())) { + log.error("Local private key is already encrypted!"); + return; + } + String challenge = RandomTool.secureRandom().nextBytes(16).asHex(); + Optional keyOpt = CardCliUtil.getChall(config.getCardCli(), challenge); + if (!keyOpt.isPresent()) { + return; + } + byte[] key = keyOpt.get(); + String localPrivateKeyPemEncrypted = AESCryptTool.gcmEncrypt(key).from(Bytes.from(config.getLocalPrivateKeyPem())).toBytes().asBase64(); + + RFile tinyEncryptConfigRFile = TinyEncryptArgsUtil.getTinyEncryptConfigRFile(tinyEncryptArgs); + config.setLocalPrivateKeyPem(null); + config.setLocalPrivateKeyPemChallenge(challenge); + config.setLocalPrivateKeyPemEncrypted(localPrivateKeyPemEncrypted); + tinyEncryptConfigRFile.write(JSONUtil.pretty(config)); + log.info("Write file success: " + tinyEncryptConfigRFile.file()); } private static void doInitConfig(TinyEncryptArgs tinyEncryptArgs) { @@ -56,12 +74,7 @@ public class TinyEncryptMain { log.error("Default key is not assigned"); return; } - RFile writeTinyEncryptConfigRFile; - if (tinyEncryptArgs.config != null) { - writeTinyEncryptConfigRFile = RFile.from(tinyEncryptArgs.config); - } else { - writeTinyEncryptConfigRFile = RFile.from(DEFAULT_TINY_ENCRYPT_CONFIG); - } + RFile writeTinyEncryptConfigRFile = TinyEncryptArgsUtil.getTinyEncryptConfigRFile(tinyEncryptArgs); if (writeTinyEncryptConfigRFile.exists()) { log.error("File exists: " + tinyEncryptArgs.config); return; @@ -134,27 +147,8 @@ public class TinyEncryptMain { } } - private static TinyEncryptConfig loadTinyEncryptConfig(TinyEncryptArgs tinyEncryptArgs) { - TinyEncryptConfig config; - if (tinyEncryptArgs.config != null) { - config = RFile.from(tinyEncryptArgs.config).parseJSONObject(TinyEncryptConfig.class); - } else { - RFile defaultTinyEncryptConfigFile = RFile.from(DEFAULT_TINY_ENCRYPT_CONFIG); - if (defaultTinyEncryptConfigFile.notExists()) { - log.error("Config file not assigned, and no default config file: " + DEFAULT_TINY_ENCRYPT_CONFIG); - return null; - } - config = defaultTinyEncryptConfigFile.parseJSONObject(TinyEncryptConfig.class); - } - if (StringUtil.isNotBlank(tinyEncryptArgs.key)) { - log.info("Using key from args: " + tinyEncryptArgs.key); - config.setDefaultKeyName(tinyEncryptArgs.key); - } - return config; - } - public static void main(String[] args) { - TinyEncryptArgs tinyEncryptArgs = parseTinyEncryptArgs(args); + TinyEncryptArgs tinyEncryptArgs = TinyEncryptArgsUtil.parseTinyEncryptArgs(args); if (tinyEncryptArgs == null) { return; } @@ -164,6 +158,10 @@ public class TinyEncryptMain { doInitConfig(tinyEncryptArgs); return; } + if (tinyEncryptArgs.doEncryptConfigLocalPrivateKey) { // --encrypt-config-local-private-key + doEncryptConfigLocalPrivateKey(tinyEncryptArgs); + return; + } if (tinyEncryptArgs.fileInfo) { // --info fileInfo(tinyEncryptArgs); return; @@ -181,7 +179,7 @@ public class TinyEncryptMain { return; } - TinyEncryptConfig config = loadTinyEncryptConfig(tinyEncryptArgs); + TinyEncryptConfig config = TinyEncryptMainUtil.loadTinyEncryptConfig(tinyEncryptArgs); if (config == null) { return; } @@ -236,8 +234,10 @@ public class TinyEncryptMain { index++; } } catch (JumpOutException joe) { - log.error(joe.getMessage()); - log.debug(joe.getMessage(), joe); + if (StringUtil.isNotEmpty(joe.getMessage())) { + log.error(joe.getMessage()); + log.debug(joe.getMessage(), joe); + } } System.exit(0); } diff --git a/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptMainUtil.java b/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptMainUtil.java new file mode 100644 index 0000000..90819e9 --- /dev/null +++ b/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptMainUtil.java @@ -0,0 +1,25 @@ +package me.hatter.tools.tinyencrypt; + +import me.hatter.tools.commons.io.RFile; +import me.hatter.tools.commons.log.LogTool; +import me.hatter.tools.commons.log.LogTools; +import me.hatter.tools.commons.string.StringUtil; +import me.hatter.tools.tinyencrypt.config.TinyEncryptConfig; + +public class TinyEncryptMainUtil { + private static final LogTool log = LogTools.getLogTool(TinyEncryptMainUtil.class); + + public static TinyEncryptConfig loadTinyEncryptConfig(TinyEncryptArgs tinyEncryptArgs) { + RFile tinyEncryptConfigRFile = TinyEncryptArgsUtil.getTinyEncryptConfigRFile(tinyEncryptArgs); + if (tinyEncryptConfigRFile.notExists()) { + log.error("Config file not found: " + tinyEncryptConfigRFile.file()); + return null; + } + TinyEncryptConfig config = tinyEncryptConfigRFile.parseJSONObject(TinyEncryptConfig.class); + if (StringUtil.isNotBlank(tinyEncryptArgs.key)) { + log.info("Using key from args: " + tinyEncryptArgs.key); + config.setDefaultKeyName(tinyEncryptArgs.key); + } + return config; + } +} diff --git a/src/main/java/me/hatter/tools/tinyencrypt/config/TinyEncryptConfig.java b/src/main/java/me/hatter/tools/tinyencrypt/config/TinyEncryptConfig.java index 3c9bee9..4131de2 100644 --- a/src/main/java/me/hatter/tools/tinyencrypt/config/TinyEncryptConfig.java +++ b/src/main/java/me/hatter/tools/tinyencrypt/config/TinyEncryptConfig.java @@ -1,11 +1,17 @@ package me.hatter.tools.tinyencrypt.config; +import me.hatter.tools.commons.string.StringUtil; + public class TinyEncryptConfig { private String defaultKeyName; private String localPublicKeyPem; private String localPrivateKeyPem; + private String localPrivateKeyPemEncrypted; + private String localPrivateKeyPemChallenge; private String pgpEncryptPublicKeyPem; + @Deprecated private String pgpDecryptCmd; + private String cardCli; public String getDefaultKeyName() { return defaultKeyName; @@ -31,6 +37,22 @@ public class TinyEncryptConfig { this.localPrivateKeyPem = localPrivateKeyPem; } + public String getLocalPrivateKeyPemEncrypted() { + return localPrivateKeyPemEncrypted; + } + + public void setLocalPrivateKeyPemEncrypted(String localPrivateKeyPemEncrypted) { + this.localPrivateKeyPemEncrypted = localPrivateKeyPemEncrypted; + } + + public String getLocalPrivateKeyPemChallenge() { + return localPrivateKeyPemChallenge; + } + + public void setLocalPrivateKeyPemChallenge(String localPrivateKeyPemChallenge) { + this.localPrivateKeyPemChallenge = localPrivateKeyPemChallenge; + } + public String getPgpEncryptPublicKeyPem() { return pgpEncryptPublicKeyPem; } @@ -46,4 +68,12 @@ public class TinyEncryptConfig { public void setPgpDecryptCmd(String pgpDecryptCmd) { this.pgpDecryptCmd = pgpDecryptCmd; } + + public String getCardCli() { + return StringUtil.def(cardCli, pgpDecryptCmd); + } + + public void setCardCli(String cardCli) { + this.cardCli = cardCli; + } } diff --git a/src/main/java/me/hatter/tools/tinyencrypt/config/TinyEncryptConstant.java b/src/main/java/me/hatter/tools/tinyencrypt/config/TinyEncryptConstant.java index 2817d8c..8a1f141 100644 --- a/src/main/java/me/hatter/tools/tinyencrypt/config/TinyEncryptConstant.java +++ b/src/main/java/me/hatter/tools/tinyencrypt/config/TinyEncryptConstant.java @@ -1,7 +1,7 @@ package me.hatter.tools.tinyencrypt.config; public class TinyEncryptConstant { - public static final String VERSION = "0.3.9"; + public static final String VERSION = "0.3.10"; public static final String ENC_FILE_EXT = ".tinyenc"; } diff --git a/src/main/java/me/hatter/tools/tinyencrypt/encrypt/EncryptedFileUtil.java b/src/main/java/me/hatter/tools/tinyencrypt/encrypt/EncryptedFileUtil.java index 67eafd6..c7aa165 100644 --- a/src/main/java/me/hatter/tools/tinyencrypt/encrypt/EncryptedFileUtil.java +++ b/src/main/java/me/hatter/tools/tinyencrypt/encrypt/EncryptedFileUtil.java @@ -1,7 +1,5 @@ package me.hatter.tools.tinyencrypt.encrypt; -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; import me.hatter.tools.commons.assertion.AssertUtil; import me.hatter.tools.commons.bytes.Bytes; import me.hatter.tools.commons.io.DefaultRollCounter; @@ -18,11 +16,13 @@ import me.hatter.tools.commons.tlv.Tlv; import me.hatter.tools.commons.tlv.TlvUtil; import me.hatter.tools.tinyencrypt.config.TinyEncryptConfig; import me.hatter.tools.tinyencrypt.config.TinyEncryptConstant; +import me.hatter.tools.tinyencrypt.util.CardCliUtil; import me.hatter.tools.tinyencrypt.util.NilOutputStream; import me.hatter.tools.tinyencrypt.util.SwingWindow; import java.io.*; import java.nio.charset.StandardCharsets; +import java.util.Optional; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; @@ -45,44 +45,25 @@ public class EncryptedFileUtil { log.error("File is not encrypted with PGP envelop"); return false; } - if (StringUtil.isBlank(config.getPgpDecryptCmd())) { - log.error("PGP decrypt cmd is not configed"); + if (StringUtil.isBlank(config.getCardCli())) { + log.error("Card-cli is empty!"); return false; } - if (RFile.from(config.getPgpDecryptCmd()).isNotFile()) { + if (RFile.from(config.getCardCli()).isNotFile()) { log.error("PGP decrypt cmd is miss configed"); return false; } - System.out.print("Input PGP PIN: "); - char[] pin = System.console().readPassword(); - if (pin.length < 6) { - log.error("PIN must have 6 letters"); + Optional pinOpt = CardCliUtil.readUserPin(); + if (!pinOpt.isPresent()) { return false; } - ProcessBuilder pb = new ProcessBuilder( - config.getPgpDecryptCmd(), - "pgp-card-decrypt", - "--cipher-base64", meta.getPgpEnvelop(), - "--pass", new String(pin), - "--json"); - log.info("Start: " + config.getPgpDecryptCmd()); - log.debug("Start process: " + pb.command()); - Process p = pb.start(); - p.waitFor(); - log.info("Finished command"); - try { - byte[] jsonBytes = IOUtil.readToBytes(p.getInputStream()); - String jsonStr = new String(jsonBytes, StandardCharsets.UTF_8); - if (log.isDebugEnable()) { - log.debug("Read cmd JSON: " + jsonStr); - } - JSONObject jo = JSON.parseObject(jsonStr); - dataKey = Bytes.fromHex(jo.getString("text_hex")).bytes(); - } catch (Exception e) { - log.error("Error in parse pgp-card-decrypt: " + e, e); - log.error("err out: " + Bytes.from(IOUtil.readToBytes(p.getErrorStream()))); + String pin = pinOpt.get(); + Optional dataKeyOpt = CardCliUtil.decryptPgpEnvelop( + config.getCardCli(), pin, meta.getPgpEnvelop()); + if (!dataKeyOpt.isPresent()) { return false; } + dataKey = dataKeyOpt.get(); } else { dataKey = TinyEncryptMetaUtil.decryptDataKey(config, meta); } diff --git a/src/main/java/me/hatter/tools/tinyencrypt/encrypt/TinyEncryptMetaUtil.java b/src/main/java/me/hatter/tools/tinyencrypt/encrypt/TinyEncryptMetaUtil.java index 1bfe404..84ae5ab 100644 --- a/src/main/java/me/hatter/tools/tinyencrypt/encrypt/TinyEncryptMetaUtil.java +++ b/src/main/java/me/hatter/tools/tinyencrypt/encrypt/TinyEncryptMetaUtil.java @@ -8,6 +8,7 @@ import me.hatter.tools.commons.log.LogTool; import me.hatter.tools.commons.log.LogTools; import me.hatter.tools.commons.network.HttpRequest; import me.hatter.tools.commons.os.OSUtil; +import me.hatter.tools.commons.security.crypt.AESCryptTool; import me.hatter.tools.commons.security.digest.Digests; import me.hatter.tools.commons.security.key.KeyUtil; import me.hatter.tools.commons.security.random.RandomTool; @@ -16,6 +17,7 @@ import me.hatter.tools.commons.security.sign.Signatures; import me.hatter.tools.commons.string.StringUtil; import me.hatter.tools.tinyencrypt.config.TinyEncryptConfig; import me.hatter.tools.tinyencrypt.config.TinyEncryptConstant; +import me.hatter.tools.tinyencrypt.util.CardCliUtil; import java.security.PrivateKey; import java.security.PublicKey; @@ -23,6 +25,7 @@ import java.security.interfaces.RSAPublicKey; import java.util.ArrayList; import java.util.Base64; import java.util.List; +import java.util.Optional; public class TinyEncryptMetaUtil { private static final LogTool log = LogTools.getLogTool(TinyEncryptMetaUtil.class); @@ -37,7 +40,27 @@ public class TinyEncryptMetaUtil { return JSON.parseObject(meta, TinyEncryptMeta.class); } + public static void requireLocalPrivateKeyPem(TinyEncryptConfig config) { + if (StringUtil.isNotEmpty(config.getLocalPrivateKeyPem())) { + return; + } + if (StringUtil.isEmpty(config.getLocalPrivateKeyPemChallenge()) + || StringUtil.isEmpty(config.getLocalPrivateKeyPemEncrypted())) { + throw new JumpOutException("Cannot prepare local private key pem!"); + } + Optional keyOpt = CardCliUtil.getChall(config.getCardCli(), config.getLocalPrivateKeyPemChallenge()); + if (!keyOpt.isPresent()) { + throw new JumpOutException(); + } + byte[] key = keyOpt.get(); + String localPrivateKeyPem = AESCryptTool.gcmDecrypt(key) + .from(Bytes.fromBase64(config.getLocalPrivateKeyPemEncrypted())).toBytes().string(); + log.info("Decrypt local private key success!"); + config.setLocalPrivateKeyPem(localPrivateKeyPem); + } + public static byte[] decryptDataKey(TinyEncryptConfig config, TinyEncryptMeta meta) { + requireLocalPrivateKeyPem(config); PrivateKey privateKey = KeyUtil.parsePrivateKeyPEM(config.getLocalPrivateKeyPem()); String envelop = meta.getEnvelop(); @@ -63,6 +86,7 @@ public class TinyEncryptMetaUtil { } public static TinyEncryptMeta create(TinyEncryptConfig config, String comment) { + requireLocalPrivateKeyPem(config); PublicKey publicKey = KeyUtil.parsePublicKeyPEM(config.getLocalPublicKeyPem()); PrivateKey privateKey = KeyUtil.parsePrivateKeyPEM(config.getLocalPrivateKeyPem()); PublicKey pgpEncryptPublicKey = null; diff --git a/src/main/java/me/hatter/tools/tinyencrypt/util/CardCliUtil.java b/src/main/java/me/hatter/tools/tinyencrypt/util/CardCliUtil.java new file mode 100644 index 0000000..fad70f5 --- /dev/null +++ b/src/main/java/me/hatter/tools/tinyencrypt/util/CardCliUtil.java @@ -0,0 +1,85 @@ +package me.hatter.tools.tinyencrypt.util; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import me.hatter.tools.commons.bytes.Bytes; +import me.hatter.tools.commons.exception.JumpOutException; +import me.hatter.tools.commons.io.IOUtil; +import me.hatter.tools.commons.log.LogTool; +import me.hatter.tools.commons.log.LogTools; +import me.hatter.tools.commons.string.StringUtil; + +import java.nio.charset.StandardCharsets; +import java.util.Optional; + +public class CardCliUtil { + private static final LogTool log = LogTools.getLogTool(CardCliUtil.class); + + public static Optional readUserPin() { + System.out.print("Input PGP user PIN: "); + char[] pin = System.console().readPassword(); + if (pin.length < 6) { + log.error("User PIN must have 6 letters"); + return Optional.empty(); + } + return Optional.of(new String(pin)); + } + + public static Optional getChall(String cardCli, String challenge) { + if (StringUtil.isEmpty(cardCli)) { + throw new JumpOutException("Card-cli is empty!"); + } + ProcessBuilder pb = new ProcessBuilder( + cardCli, + "chall", + "--challenge-hex", challenge, + "--json", "--sha256"); + log.info("Start: " + cardCli); + + Optional outputsOpt = runProcess(pb); + if (!outputsOpt.isPresent()) { + return Optional.empty(); + } + JSONObject jo = JSON.parseObject(outputsOpt.get()); + return Optional.of(Bytes.fromHex(jo.getString("response_sha256_hex")).bytes()); + } + + public static Optional decryptPgpEnvelop(String cardCli, String pin, String pgpEnvelop) { + ProcessBuilder pb = new ProcessBuilder( + cardCli, + "pgp-card-decrypt", + "--cipher-base64", pgpEnvelop, + "--pin", pin, + "--json"); + log.info("Start: " + cardCli); + Optional outputsOpt = runProcess(pb); + if (!outputsOpt.isPresent()) { + return Optional.empty(); + } + JSONObject jo = JSON.parseObject(outputsOpt.get()); + return Optional.of(Bytes.fromHex(jo.getString("text_hex")).bytes()); + } + + public static Optional runProcess(ProcessBuilder pb) { + Process p = null; + try { + log.debug("Start process: " + pb.command()); + p = pb.start(); + p.waitFor(); + log.info("Finished command"); + + byte[] jsonBytes = IOUtil.readToBytes(p.getInputStream()); + String outputs = new String(jsonBytes, StandardCharsets.UTF_8); + if (log.isDebugEnable()) { + log.debug("Read cmd outputs: " + outputs); + } + return Optional.of(outputs); + } catch (Exception e) { + log.error("Error in run card-cli: " + e, e); + if (p != null) { + log.error("err out: " + Bytes.from(IOUtil.readToBytes(p.getErrorStream()))); + } + return Optional.empty(); + } + } +}