feat: v0.5.3
This commit is contained in:
@@ -8,8 +8,8 @@ public class TinyEncryptArgsUtil {
|
|||||||
|
|
||||||
|
|
||||||
public static TinyEncryptArgs parseTinyEncryptArgs(String[] args) {
|
public static TinyEncryptArgs parseTinyEncryptArgs(String[] args) {
|
||||||
TinyEncryptArgs tinyEncryptArgs = new TinyEncryptArgs();
|
final TinyEncryptArgs tinyEncryptArgs = new TinyEncryptArgs();
|
||||||
CommandLine cmd = new CommandLine(tinyEncryptArgs);
|
final CommandLine cmd = new CommandLine(tinyEncryptArgs);
|
||||||
cmd.parseArgs(args);
|
cmd.parseArgs(args);
|
||||||
|
|
||||||
if (cmd.isUsageHelpRequested()) {
|
if (cmd.isUsageHelpRequested()) {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public class TinyEncryptMain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
TinyEncryptArgs tinyEncryptArgs = TinyEncryptArgsUtil.parseTinyEncryptArgs(args);
|
final TinyEncryptArgs tinyEncryptArgs = TinyEncryptArgsUtil.parseTinyEncryptArgs(args);
|
||||||
if (tinyEncryptArgs == null) {
|
if (tinyEncryptArgs == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -44,9 +44,9 @@ public class TinyEncryptMain {
|
|||||||
}
|
}
|
||||||
// ====================================================================================
|
// ====================================================================================
|
||||||
|
|
||||||
boolean isCreate = tinyEncryptArgs.create;
|
final boolean isCreate = tinyEncryptArgs.create;
|
||||||
boolean isEncrypt = tinyEncryptArgs.encrypt;
|
final boolean isEncrypt = tinyEncryptArgs.encrypt;
|
||||||
boolean isDecrypt = tinyEncryptArgs.decrypt;
|
final boolean isDecrypt = tinyEncryptArgs.decrypt;
|
||||||
if ((isEncrypt && isDecrypt) || (isCreate && isEncrypt) || (isCreate && isDecrypt)) {
|
if ((isEncrypt && isDecrypt) || (isCreate && isEncrypt) || (isCreate && isDecrypt)) {
|
||||||
log.error("Encrypt create or decrypt flag cannot multiple assigned.");
|
log.error("Encrypt create or decrypt flag cannot multiple assigned.");
|
||||||
return;
|
return;
|
||||||
@@ -56,7 +56,7 @@ public class TinyEncryptMain {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TinyEncryptConfig config = TinyEncryptMainUtil.loadTinyEncryptConfig(tinyEncryptArgs);
|
final TinyEncryptConfig config = TinyEncryptMainUtil.loadTinyEncryptConfig(tinyEncryptArgs);
|
||||||
if (config == null) {
|
if (config == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -67,54 +67,54 @@ public class TinyEncryptMain {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (isCreate) {
|
if (isCreate) {
|
||||||
TinyEncryptMainUtil.crateFileFromWindow(tinyEncryptArgs, config);
|
TinyEncryptMainUtil.createFileFromWindow(tinyEncryptArgs, config);
|
||||||
throw new JumpOutException();
|
throw new JumpOutException();
|
||||||
}
|
}
|
||||||
|
|
||||||
int index = 1;
|
int index = 1;
|
||||||
int total = tinyEncryptArgs.files.length;
|
final int total = tinyEncryptArgs.files.length;
|
||||||
for (File f : tinyEncryptArgs.files) {
|
for (File f : tinyEncryptArgs.files) {
|
||||||
log.info("Start processing file: " + f + ", " + index + " of " + total);
|
log.info("Start processing file: " + f + ", " + index + " of " + total);
|
||||||
|
index++;
|
||||||
if (!f.isFile()) {
|
if (!f.isFile()) {
|
||||||
log.info("Skip not a file: " + f);
|
log.info("Skip not a file: " + f);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
boolean decryptSuccess;
|
final boolean encryptOrDecryptSuccess;
|
||||||
if (tinyEncryptArgs.encrypt) {
|
if (tinyEncryptArgs.encrypt) {
|
||||||
decryptSuccess = EncryptedFileUtil.encryptFile(config, tinyEncryptArgs.key, f,
|
encryptOrDecryptSuccess = EncryptedFileUtil.encryptFile(config, tinyEncryptArgs.key, f,
|
||||||
tinyEncryptArgs.compress, !tinyEncryptArgs.skipEnvelop, tinyEncryptArgs.requireSign,
|
tinyEncryptArgs.compress, !tinyEncryptArgs.skipEnvelop, tinyEncryptArgs.requireSign,
|
||||||
tinyEncryptArgs.comment, tinyEncryptArgs.encryptedComment);
|
tinyEncryptArgs.comment, tinyEncryptArgs.encryptedComment);
|
||||||
} else {
|
} else {
|
||||||
if (tinyEncryptArgs.showInWindow || tinyEncryptArgs.editInWindow) {
|
if (tinyEncryptArgs.showInWindow || tinyEncryptArgs.editInWindow) {
|
||||||
EncryptedFileUtil.decryptInWindow(config, f, tinyEncryptArgs.pgp, tinyEncryptArgs.editInWindow);
|
EncryptedFileUtil.decryptInWindow(config, f, tinyEncryptArgs.pgp, tinyEncryptArgs.editInWindow);
|
||||||
decryptSuccess = false; // do not delete file
|
encryptOrDecryptSuccess = false; // do not delete file
|
||||||
} else if (tinyEncryptArgs.digest) {
|
} else if (tinyEncryptArgs.digest) {
|
||||||
Bytes sha256 = EncryptedFileUtil.decryptAndDigest(config, f, tinyEncryptArgs.pgp);
|
final Bytes sha256 = EncryptedFileUtil.decryptAndDigest(config, f, tinyEncryptArgs.pgp);
|
||||||
if (sha256 != null) {
|
if (sha256 != null) {
|
||||||
log.info(sha256.asHex() + " - " + f);
|
log.info(sha256.asHex() + " - " + f);
|
||||||
File clearTextFile = EncryptedFileUtil.getDecryptFile(f);
|
final File clearTextFile = EncryptedFileUtil.getDecryptFile(f);
|
||||||
if ((clearTextFile != null) && clearTextFile.exists()) {
|
if ((clearTextFile != null) && clearTextFile.exists()) {
|
||||||
Bytes clearTextSha256 = RFile.from(clearTextFile).digest(Digests.sha256());
|
final Bytes clearTextSha256 = RFile.from(clearTextFile).digest(Digests.sha256());
|
||||||
if (clearTextSha256.equals(sha256)) {
|
if (clearTextSha256.equals(sha256)) {
|
||||||
log.info("Clear text file exists, and MATCHES.");
|
log.info("Clear text file exists, and MATCHES.");
|
||||||
} else {
|
} else {
|
||||||
String nfn = f.toString();
|
final String nfn = f.toString();
|
||||||
log.warn(clearTextSha256.asHex() + " - " + nfn.substring(0, nfn.length() - TinyEncryptConstant.ENC_FILE_EXT.length()));
|
log.warn(clearTextSha256.asHex() + " - " + nfn.substring(0, nfn.length() - TinyEncryptConstant.ENC_FILE_EXT.length()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
decryptSuccess = false; // do not delete file
|
encryptOrDecryptSuccess = false; // do not delete file
|
||||||
} else {
|
} else {
|
||||||
decryptSuccess = EncryptedFileUtil.decryptFile(config, f, tinyEncryptArgs.pgp);
|
encryptOrDecryptSuccess = EncryptedFileUtil.decryptFile(config, f, tinyEncryptArgs.pgp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (decryptSuccess && tinyEncryptArgs.removeFile) {
|
if (encryptOrDecryptSuccess && tinyEncryptArgs.removeFile) {
|
||||||
log.info("Remove file: " + f);
|
log.info("Remove file: " + f);
|
||||||
if (!f.delete()) {
|
if (!f.delete()) {
|
||||||
log.warn("Remove file: " + f + " failed.");
|
log.warn("Remove file: " + f + " failed.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
index++;
|
|
||||||
}
|
}
|
||||||
} catch (JumpOutException joe) {
|
} catch (JumpOutException joe) {
|
||||||
if (StringUtil.isNotEmpty(joe.getMessage())) {
|
if (StringUtil.isNotEmpty(joe.getMessage())) {
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ public class TinyEncryptMainUtil {
|
|||||||
private static final LogTool log = LogTools.getLogTool(TinyEncryptMainUtil.class);
|
private static final LogTool log = LogTools.getLogTool(TinyEncryptMainUtil.class);
|
||||||
|
|
||||||
public static void encryptConfigLocalPrivateKey(TinyEncryptArgs tinyEncryptArgs) {
|
public static void encryptConfigLocalPrivateKey(TinyEncryptArgs tinyEncryptArgs) {
|
||||||
TinyEncryptConfig config = loadTinyEncryptConfig(tinyEncryptArgs);
|
final TinyEncryptConfig config = loadTinyEncryptConfig(tinyEncryptArgs);
|
||||||
if (config == null) {
|
if (config == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -47,15 +47,15 @@ public class TinyEncryptMainUtil {
|
|||||||
log.error("Local private key is already encrypted!");
|
log.error("Local private key is already encrypted!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String challenge = RandomTool.secureRandom().nextBytes(16).asHex();
|
final String challenge = RandomTool.secureRandom().nextBytes(16).asHex();
|
||||||
Optional<byte[]> keyOpt = CardCliUtil.getChall(config.getCardCli(), challenge);
|
final Optional<byte[]> keyOpt = CardCliUtil.getChall(config.getCardCli(), challenge);
|
||||||
if (!keyOpt.isPresent()) {
|
if (!keyOpt.isPresent()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
byte[] key = keyOpt.get();
|
final byte[] key = keyOpt.get();
|
||||||
String localPrivateKeyPemEncrypted = AESCryptTool.gcmEncrypt(key).from(Bytes.from(config.getLocalPrivateKeyPem())).toBytes().asBase64();
|
final String localPrivateKeyPemEncrypted = AESCryptTool.gcmEncrypt(key).from(Bytes.from(config.getLocalPrivateKeyPem())).toBytes().asBase64();
|
||||||
|
|
||||||
RFile tinyEncryptConfigRFile = TinyEncryptArgsUtil.getTinyEncryptConfigRFile(tinyEncryptArgs);
|
final RFile tinyEncryptConfigRFile = TinyEncryptArgsUtil.getTinyEncryptConfigRFile(tinyEncryptArgs);
|
||||||
config.setLocalPrivateKeyPem(null);
|
config.setLocalPrivateKeyPem(null);
|
||||||
config.setLocalPrivateKeyPemChallenge(challenge);
|
config.setLocalPrivateKeyPemChallenge(challenge);
|
||||||
config.setLocalPrivateKeyPemEncrypted(localPrivateKeyPemEncrypted);
|
config.setLocalPrivateKeyPemEncrypted(localPrivateKeyPemEncrypted);
|
||||||
@@ -68,13 +68,13 @@ public class TinyEncryptMainUtil {
|
|||||||
log.error("Default key is not assigned");
|
log.error("Default key is not assigned");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
RFile writeTinyEncryptConfigRFile = TinyEncryptArgsUtil.getTinyEncryptConfigRFile(tinyEncryptArgs);
|
final RFile writeTinyEncryptConfigRFile = TinyEncryptArgsUtil.getTinyEncryptConfigRFile(tinyEncryptArgs);
|
||||||
if (writeTinyEncryptConfigRFile.exists()) {
|
if (writeTinyEncryptConfigRFile.exists()) {
|
||||||
log.error("File exists: " + tinyEncryptArgs.config);
|
log.error("File exists: " + tinyEncryptArgs.config);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
KeyPair keyPair = KeyPairTool.ins(PKType.secp256r1).generate().getKeyPair();
|
final KeyPair keyPair = KeyPairTool.ins(PKType.secp256r1).generate().getKeyPair();
|
||||||
TinyEncryptConfig writeTinyEncryptConfig = new TinyEncryptConfig();
|
final TinyEncryptConfig writeTinyEncryptConfig = new TinyEncryptConfig();
|
||||||
writeTinyEncryptConfig.setDefaultKeyName(tinyEncryptArgs.key);
|
writeTinyEncryptConfig.setDefaultKeyName(tinyEncryptArgs.key);
|
||||||
writeTinyEncryptConfig.setLocalPublicKeyPem(KeyUtil.serializePublicKeyToPEM(keyPair.getPublic()));
|
writeTinyEncryptConfig.setLocalPublicKeyPem(KeyUtil.serializePublicKeyToPEM(keyPair.getPublic()));
|
||||||
writeTinyEncryptConfig.setLocalPrivateKeyPem(KeyUtil.serializePrivateKeyToPEM(keyPair.getPrivate()));
|
writeTinyEncryptConfig.setLocalPrivateKeyPem(KeyUtil.serializePrivateKeyToPEM(keyPair.getPrivate()));
|
||||||
@@ -88,7 +88,7 @@ public class TinyEncryptMainUtil {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (File f : tinyEncryptArgs.files) {
|
for (File f : tinyEncryptArgs.files) {
|
||||||
boolean isTinyEncFile = f.getName().endsWith(TinyEncryptConstant.ENC_FILE_EXT);
|
final boolean isTinyEncFile = f.getName().endsWith(TinyEncryptConstant.ENC_FILE_EXT);
|
||||||
if (!isTinyEncFile) {
|
if (!isTinyEncFile) {
|
||||||
log.warn("File is not tiny enc file: " + f);
|
log.warn("File is not tiny enc file: " + f);
|
||||||
} else {
|
} else {
|
||||||
@@ -104,12 +104,12 @@ public class TinyEncryptMainUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static TinyEncryptConfig loadTinyEncryptConfig(TinyEncryptArgs tinyEncryptArgs) {
|
public static TinyEncryptConfig loadTinyEncryptConfig(TinyEncryptArgs tinyEncryptArgs) {
|
||||||
RFile tinyEncryptConfigRFile = TinyEncryptArgsUtil.getTinyEncryptConfigRFile(tinyEncryptArgs);
|
final RFile tinyEncryptConfigRFile = TinyEncryptArgsUtil.getTinyEncryptConfigRFile(tinyEncryptArgs);
|
||||||
if (tinyEncryptConfigRFile.notExists()) {
|
if (tinyEncryptConfigRFile.notExists()) {
|
||||||
log.error("Config file not found: " + tinyEncryptConfigRFile.file());
|
log.error("Config file not found: " + tinyEncryptConfigRFile.file());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
TinyEncryptConfig config = tinyEncryptConfigRFile.parseJSONObject(TinyEncryptConfig.class);
|
final TinyEncryptConfig config = tinyEncryptConfigRFile.parseJSONObject(TinyEncryptConfig.class);
|
||||||
if (StringUtil.isNotBlank(tinyEncryptArgs.key)) {
|
if (StringUtil.isNotBlank(tinyEncryptArgs.key)) {
|
||||||
log.info("Using key from args: " + tinyEncryptArgs.key);
|
log.info("Using key from args: " + tinyEncryptArgs.key);
|
||||||
config.setDefaultKeyName(tinyEncryptArgs.key);
|
config.setDefaultKeyName(tinyEncryptArgs.key);
|
||||||
@@ -117,7 +117,7 @@ public class TinyEncryptMainUtil {
|
|||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void crateFileFromWindow(TinyEncryptArgs tinyEncryptArgs, TinyEncryptConfig config) {
|
public static void createFileFromWindow(TinyEncryptArgs tinyEncryptArgs, TinyEncryptConfig config) {
|
||||||
if (tinyEncryptArgs.files.length != 1) {
|
if (tinyEncryptArgs.files.length != 1) {
|
||||||
log.error("Create only can assign one file");
|
log.error("Create only can assign one file");
|
||||||
return;
|
return;
|
||||||
@@ -132,14 +132,14 @@ public class TinyEncryptMainUtil {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String editResult = SwingWindow.create("Create file: " + file.getName())
|
final String editResult = SwingWindow.create("Create file: " + file.getName())
|
||||||
.message("File: " + file)
|
.message("File: " + file)
|
||||||
.text("")
|
.text("")
|
||||||
.editable(true)
|
.editable(true)
|
||||||
.show().getResult();
|
.show().getResult();
|
||||||
|
|
||||||
byte[] bytes = editResult.getBytes(StandardCharsets.UTF_8);
|
final byte[] bytes = editResult.getBytes(StandardCharsets.UTF_8);
|
||||||
TinyEncryptMeta meta = TinyEncryptMetaUtil.create(config, tinyEncryptArgs.key,
|
final TinyEncryptMeta meta = TinyEncryptMetaUtil.create(config, tinyEncryptArgs.key,
|
||||||
tinyEncryptArgs.comment, tinyEncryptArgs.encryptedComment,
|
tinyEncryptArgs.comment, tinyEncryptArgs.encryptedComment,
|
||||||
!tinyEncryptArgs.skipEnvelop, tinyEncryptArgs.requireSign);
|
!tinyEncryptArgs.skipEnvelop, tinyEncryptArgs.requireSign);
|
||||||
meta.setFileLength((long) bytes.length);
|
meta.setFileLength((long) bytes.length);
|
||||||
@@ -147,7 +147,7 @@ public class TinyEncryptMainUtil {
|
|||||||
meta.setFileLastModified(System.currentTimeMillis());
|
meta.setFileLastModified(System.currentTimeMillis());
|
||||||
meta.setCompress(tinyEncryptArgs.compress);
|
meta.setCompress(tinyEncryptArgs.compress);
|
||||||
|
|
||||||
InputStream inputStream = new ByteArrayInputStream(bytes);
|
final InputStream inputStream = new ByteArrayInputStream(bytes);
|
||||||
try {
|
try {
|
||||||
EncryptedFileUtil.encryptFromInputStream(inputStream, file, meta);
|
EncryptedFileUtil.encryptFromInputStream(inputStream, file, meta);
|
||||||
log.info("Create file: " + file + " success");
|
log.info("Create file: " + file + " success");
|
||||||
@@ -157,10 +157,10 @@ public class TinyEncryptMainUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void printOneFileInfo(File f, FileInputStream fis) throws IOException {
|
private static void printOneFileInfo(File f, FileInputStream fis) throws IOException {
|
||||||
Tlv tlv = TlvUtil.readTlv(fis);
|
final Tlv tlv = TlvUtil.readTlv(fis);
|
||||||
TinyEncryptMeta meta = tlv.getValueAsBytes().asJSONObject(TinyEncryptMeta.class);
|
final TinyEncryptMeta meta = tlv.getValueAsBytes().asJSONObject(TinyEncryptMeta.class);
|
||||||
log.debug("Tiny encrypt meta: " + JSON.toJSONString(meta, true));
|
log.debug("Tiny encrypt meta: " + JSON.toJSONString(meta, true));
|
||||||
StringBuilder sb = new StringBuilder(256);
|
final StringBuilder sb = new StringBuilder(256);
|
||||||
sb.append("Tiny Encrypt File Info\n");
|
sb.append("Tiny Encrypt File Info\n");
|
||||||
sb.append(header("File")).append(f);
|
sb.append(header("File")).append(f);
|
||||||
if ((meta.getCompress() != null) && meta.getCompress()) {
|
if ((meta.getCompress() != null) && meta.getCompress()) {
|
||||||
@@ -196,7 +196,7 @@ public class TinyEncryptMainUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static String header(String h) {
|
private static String header(String h) {
|
||||||
int width = 18;
|
final int width = 18;
|
||||||
return h + StringUtil.repeat(".", Math.max(width - h.length(), 0)) + ": ";
|
return h + StringUtil.repeat(".", Math.max(width - h.length(), 0)) + ": ";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package me.hatter.tools.tinyencrypt.config;
|
package me.hatter.tools.tinyencrypt.config;
|
||||||
|
|
||||||
public class TinyEncryptConstant {
|
public class TinyEncryptConstant {
|
||||||
public static final String VERSION = "0.5.2";
|
public static final String VERSION = "0.5.3";
|
||||||
|
|
||||||
public static final String ENC_FILE_EXT = ".tinyenc";
|
public static final String ENC_FILE_EXT = ".tinyenc";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import me.hatter.tools.tinyencrypt.util.SwingWindow;
|
|||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.zip.GZIPInputStream;
|
import java.util.zip.GZIPInputStream;
|
||||||
@@ -38,13 +39,13 @@ public class EncryptedFileUtil {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
try (FileInputStream fis = new FileInputStream(file)) {
|
try (FileInputStream fis = new FileInputStream(file)) {
|
||||||
Tlv tlv = TlvUtil.readTlv(fis);
|
final Tlv tlv = TlvUtil.readTlv(fis);
|
||||||
TinyEncryptMeta meta = tlv.getValueAsBytes().asJSONObject(TinyEncryptMeta.class);
|
final TinyEncryptMeta meta = tlv.getValueAsBytes().asJSONObject(TinyEncryptMeta.class);
|
||||||
if (metaRef != null) {
|
if (metaRef != null) {
|
||||||
metaRef.set(meta);
|
metaRef.set(meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] dataKey;
|
final byte[] dataKey;
|
||||||
if (pgp) {
|
if (pgp) {
|
||||||
if (StringUtil.isBlank(meta.getPgpEnvelop())) {
|
if (StringUtil.isBlank(meta.getPgpEnvelop())) {
|
||||||
log.error("File is not encrypted with PGP envelop");
|
log.error("File is not encrypted with PGP envelop");
|
||||||
@@ -58,12 +59,12 @@ public class EncryptedFileUtil {
|
|||||||
log.error("PGP decrypt cmd is miss configed");
|
log.error("PGP decrypt cmd is miss configed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Optional<String> pinOpt = CardCliUtil.readUserPin();
|
final Optional<String> pinOpt = CardCliUtil.readUserPin();
|
||||||
if (!pinOpt.isPresent()) {
|
if (!pinOpt.isPresent()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
String pin = pinOpt.get();
|
final String pin = pinOpt.get();
|
||||||
Optional<byte[]> dataKeyOpt = CardCliUtil.decryptPgpEnvelop(
|
final Optional<byte[]> dataKeyOpt = CardCliUtil.decryptPgpEnvelop(
|
||||||
config.getCardCli(), pin, meta.getPgpEnvelop());
|
config.getCardCli(), pin, meta.getPgpEnvelop());
|
||||||
if (!dataKeyOpt.isPresent()) {
|
if (!dataKeyOpt.isPresent()) {
|
||||||
return false;
|
return false;
|
||||||
@@ -75,14 +76,14 @@ public class EncryptedFileUtil {
|
|||||||
meta.setDataKey(dataKey);
|
meta.setDataKey(dataKey);
|
||||||
|
|
||||||
if (StringUtil.isNotEmpty(meta.getEncryptedComment())) {
|
if (StringUtil.isNotEmpty(meta.getEncryptedComment())) {
|
||||||
Bytes decryptedComment = AESCryptTool.gcmDecrypt(meta.getDataKey(), meta.getNonce())
|
final Bytes decryptedComment = AESCryptTool.gcmDecrypt(meta.getDataKey(), meta.getNonce())
|
||||||
.from(Bytes.fromBase64(meta.getEncryptedComment()))
|
.from(Bytes.fromBase64(meta.getEncryptedComment()))
|
||||||
.toBytes();
|
.toBytes();
|
||||||
log.info("Decrypted comment: >>> " + decryptedComment.string() + " <<<");
|
log.info("Decrypted comment: >>> " + decryptedComment.string() + " <<<");
|
||||||
}
|
}
|
||||||
|
|
||||||
try (InputStream newIs = getDecryptInputStream(fis, meta)) {
|
try (InputStream newIs = getDecryptInputStream(fis, meta)) {
|
||||||
boolean isCompressed = (meta.getCompress() != null) && meta.getCompress();
|
final boolean isCompressed = (meta.getCompress() != null) && meta.getCompress();
|
||||||
if (isCompressed) {
|
if (isCompressed) {
|
||||||
GZIPInputStream gzIs = new GZIPInputStream(newIs);
|
GZIPInputStream gzIs = new GZIPInputStream(newIs);
|
||||||
IOUtil.copy(gzIs, os, new DefaultRollCounter().prefix("Decrypting, "));
|
IOUtil.copy(gzIs, os, new DefaultRollCounter().prefix("Decrypting, "));
|
||||||
@@ -102,7 +103,7 @@ public class EncryptedFileUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Bytes decryptAndDigest(TinyEncryptConfig config, File file, boolean pgp) {
|
public static Bytes decryptAndDigest(TinyEncryptConfig config, File file, boolean pgp) {
|
||||||
DigestOutputStream outputStream = new DigestOutputStream(new NilOutputStream(), Digests.sha256());
|
final DigestOutputStream outputStream = new DigestOutputStream(new NilOutputStream(), Digests.sha256());
|
||||||
if (!decryptToOutputStream(config, file, outputStream, pgp, null)) {
|
if (!decryptToOutputStream(config, file, outputStream, pgp, null)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -110,15 +111,15 @@ public class EncryptedFileUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void decryptInWindow(TinyEncryptConfig config, File file, boolean pgp, boolean editable) {
|
public static void decryptInWindow(TinyEncryptConfig config, File file, boolean pgp, boolean editable) {
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
AtomicReference<TinyEncryptMeta> metaRef = new AtomicReference<>();
|
final AtomicReference<TinyEncryptMeta> metaRef = new AtomicReference<>();
|
||||||
boolean decryptSuccess = decryptToOutputStream(config, file, baos, pgp, metaRef);
|
final boolean decryptSuccess = decryptToOutputStream(config, file, baos, pgp, metaRef);
|
||||||
if (!decryptSuccess) {
|
if (!decryptSuccess) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String decrypted = new String(baos.toByteArray(), StandardCharsets.UTF_8);
|
final String decrypted = new String(baos.toByteArray(), StandardCharsets.UTF_8);
|
||||||
String editResult = SwingWindow.create((editable ? "Edit" : "View") + " file: " + file.getName())
|
final String editResult = SwingWindow.create((editable ? "Edit" : "View") + " file: " + file.getName())
|
||||||
.message("File: " + file)
|
.message("File: " + file)
|
||||||
.text(decrypted)
|
.text(decrypted)
|
||||||
.editable(editable)
|
.editable(editable)
|
||||||
@@ -130,10 +131,10 @@ public class EncryptedFileUtil {
|
|||||||
log.warn("Text is not modified");
|
log.warn("Text is not modified");
|
||||||
} else {
|
} else {
|
||||||
log.debug("Write to encrypt file: " + file);
|
log.debug("Write to encrypt file: " + file);
|
||||||
byte[] bytes = editResult.getBytes(StandardCharsets.UTF_8);
|
final byte[] bytes = editResult.getBytes(StandardCharsets.UTF_8);
|
||||||
InputStream inputStream = new ByteArrayInputStream(bytes);
|
final InputStream inputStream = new ByteArrayInputStream(bytes);
|
||||||
try {
|
try {
|
||||||
TinyEncryptMeta meta = metaRef.get();
|
final TinyEncryptMeta meta = metaRef.get();
|
||||||
meta.setFileLength((long) bytes.length);
|
meta.setFileLength((long) bytes.length);
|
||||||
meta.setFileLastModified(System.currentTimeMillis());
|
meta.setFileLastModified(System.currentTimeMillis());
|
||||||
encryptFromInputStream(inputStream, file, meta);
|
encryptFromInputStream(inputStream, file, meta);
|
||||||
@@ -146,7 +147,7 @@ public class EncryptedFileUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean decryptFile(TinyEncryptConfig config, File file, boolean pgp) {
|
public static boolean decryptFile(TinyEncryptConfig config, File file, boolean pgp) {
|
||||||
File decFile = getDecryptFile(file);
|
final File decFile = getDecryptFile(file);
|
||||||
if (decFile == null) {
|
if (decFile == null) {
|
||||||
log.warn("File is not tinyenc file, skip: " + decFile);
|
log.warn("File is not tinyenc file, skip: " + decFile);
|
||||||
return false;
|
return false;
|
||||||
@@ -156,9 +157,10 @@ public class EncryptedFileUtil {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
boolean decryptResult;
|
final AtomicReference<TinyEncryptMeta> meta = new AtomicReference<>();
|
||||||
|
final boolean decryptResult;
|
||||||
try (FileOutputStream fos = new FileOutputStream(decFile)) {
|
try (FileOutputStream fos = new FileOutputStream(decFile)) {
|
||||||
decryptResult = decryptToOutputStream(config, file, fos, pgp, null);
|
decryptResult = decryptToOutputStream(config, file, fos, pgp, meta);
|
||||||
}
|
}
|
||||||
if (!decryptResult) {
|
if (!decryptResult) {
|
||||||
if (decFile.length() == 0) {
|
if (decFile.length() == 0) {
|
||||||
@@ -166,6 +168,11 @@ public class EncryptedFileUtil {
|
|||||||
decFile.delete();
|
decFile.delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (meta.get().getFileLastModified() != null) {
|
||||||
|
log.debug("Set file last modified time to: " + new Date(meta.get().getFileLastModified()));
|
||||||
|
//noinspection ResultOfMethodCallIgnored
|
||||||
|
decFile.setLastModified(meta.get().getFileLastModified());
|
||||||
|
}
|
||||||
return decryptResult;
|
return decryptResult;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (decFile.length() == 0) {
|
if (decFile.length() == 0) {
|
||||||
|
|||||||
@@ -48,12 +48,12 @@ public class TinyEncryptMetaUtil {
|
|||||||
|| StringUtil.isEmpty(config.getLocalPrivateKeyPemEncrypted())) {
|
|| StringUtil.isEmpty(config.getLocalPrivateKeyPemEncrypted())) {
|
||||||
throw new JumpOutException("Cannot prepare local private key pem!");
|
throw new JumpOutException("Cannot prepare local private key pem!");
|
||||||
}
|
}
|
||||||
Optional<byte[]> keyOpt = CardCliUtil.getChall(config.getCardCli(), config.getLocalPrivateKeyPemChallenge());
|
final Optional<byte[]> keyOpt = CardCliUtil.getChall(config.getCardCli(), config.getLocalPrivateKeyPemChallenge());
|
||||||
if (!keyOpt.isPresent()) {
|
if (!keyOpt.isPresent()) {
|
||||||
throw new JumpOutException("Get challenge failed!");
|
throw new JumpOutException("Get challenge failed!");
|
||||||
}
|
}
|
||||||
byte[] key = keyOpt.get();
|
final byte[] key = keyOpt.get();
|
||||||
String localPrivateKeyPem = AESCryptTool.gcmDecrypt(key)
|
final String localPrivateKeyPem = AESCryptTool.gcmDecrypt(key)
|
||||||
.from(Bytes.fromBase64(config.getLocalPrivateKeyPemEncrypted())).toBytes().string();
|
.from(Bytes.fromBase64(config.getLocalPrivateKeyPemEncrypted())).toBytes().string();
|
||||||
log.info("Decrypt local private key success!");
|
log.info("Decrypt local private key success!");
|
||||||
config.setLocalPrivateKeyPem(localPrivateKeyPem);
|
config.setLocalPrivateKeyPem(localPrivateKeyPem);
|
||||||
@@ -61,30 +61,30 @@ public class TinyEncryptMetaUtil {
|
|||||||
|
|
||||||
public static byte[] decryptDataKey(TinyEncryptConfig config, TinyEncryptMeta meta) {
|
public static byte[] decryptDataKey(TinyEncryptConfig config, TinyEncryptMeta meta) {
|
||||||
requireLocalPrivateKeyPem(config);
|
requireLocalPrivateKeyPem(config);
|
||||||
PrivateKey privateKey = KeyUtil.parsePrivateKeyPEM(config.getLocalPrivateKeyPem());
|
final PrivateKey privateKey = KeyUtil.parsePrivateKeyPEM(config.getLocalPrivateKeyPem());
|
||||||
String envelop = meta.getEnvelop();
|
final String envelop = meta.getEnvelop();
|
||||||
if (StringUtil.isEmpty(envelop)) {
|
if (StringUtil.isEmpty(envelop)) {
|
||||||
throw new JumpOutException("File encryption envelop is not present");
|
throw new JumpOutException("File encryption envelop is not present");
|
||||||
}
|
}
|
||||||
|
|
||||||
String timestamp = String.valueOf(System.currentTimeMillis());
|
final String timestamp = String.valueOf(System.currentTimeMillis());
|
||||||
String toBeSigned = envelop + "|" + timestamp;
|
final String toBeSigned = envelop + "|" + timestamp;
|
||||||
Bytes sign = Signatures.sha256(privateKey).sign(toBeSigned);
|
final Bytes sign = Signatures.sha256(privateKey).sign(toBeSigned);
|
||||||
|
|
||||||
List<HttpRequest.KeyValue> keyValues = new ArrayList<>();
|
final List<HttpRequest.KeyValue> keyValues = new ArrayList<>();
|
||||||
keyValues.add(new HttpRequest.KeyValue("envelop", envelop));
|
keyValues.add(new HttpRequest.KeyValue("envelop", envelop));
|
||||||
keyValues.add(new HttpRequest.KeyValue("timestamp", timestamp));
|
keyValues.add(new HttpRequest.KeyValue("timestamp", timestamp));
|
||||||
keyValues.add(new HttpRequest.KeyValue("signature", sign.asBase64()));
|
keyValues.add(new HttpRequest.KeyValue("signature", sign.asBase64()));
|
||||||
log.info("Decrypt data key ...");
|
log.info("Decrypt data key ...");
|
||||||
Bytes response = HttpRequest.fromUrl(KMS_DECRYPT_DATA_KEY).post(keyValues);
|
final Bytes response = HttpRequest.fromUrl(KMS_DECRYPT_DATA_KEY).post(keyValues);
|
||||||
JSONObject responseObject = response.asJSON();
|
final JSONObject responseObject = response.asJSON();
|
||||||
if (responseObject.getIntValue("status") != 200) {
|
if (responseObject.getIntValue("status") != 200) {
|
||||||
throw new JumpOutException("Get data key from kms error, status: "
|
throw new JumpOutException("Get data key from kms error, status: "
|
||||||
+ responseObject.getIntValue("status")
|
+ responseObject.getIntValue("status")
|
||||||
+ ", detail: " + responseObject
|
+ ", detail: " + responseObject
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
JSONObject responseData = responseObject.getJSONObject("data");
|
final JSONObject responseData = responseObject.getJSONObject("data");
|
||||||
return Base64.getDecoder().decode(responseData.getString("dataKey"));
|
return Base64.getDecoder().decode(responseData.getString("dataKey"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ public class CardCliUtil {
|
|||||||
|
|
||||||
public static Optional<String> readUserPin() {
|
public static Optional<String> readUserPin() {
|
||||||
System.out.print("Input PGP user PIN: ");
|
System.out.print("Input PGP user PIN: ");
|
||||||
char[] pin = System.console().readPassword();
|
final char[] pin = System.console().readPassword();
|
||||||
if (pin.length < 6) {
|
if (pin.length < 6) {
|
||||||
log.error("User PIN must have 6 letters");
|
log.error("User PIN must have 6 letters");
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
@@ -29,35 +29,35 @@ public class CardCliUtil {
|
|||||||
if (StringUtil.isEmpty(cardCli)) {
|
if (StringUtil.isEmpty(cardCli)) {
|
||||||
throw new JumpOutException("Card-cli is empty!");
|
throw new JumpOutException("Card-cli is empty!");
|
||||||
}
|
}
|
||||||
ProcessBuilder pb = new ProcessBuilder(
|
final ProcessBuilder pb = new ProcessBuilder(
|
||||||
cardCli,
|
cardCli,
|
||||||
"chall",
|
"chall",
|
||||||
"--challenge-hex", challenge,
|
"--challenge-hex", challenge,
|
||||||
"--json", "--sha256");
|
"--json", "--sha256");
|
||||||
log.info("Start: " + cardCli);
|
log.info("Start: " + cardCli);
|
||||||
|
|
||||||
Optional<String> outputsOpt = runProcess(pb);
|
final Optional<String> outputsOpt = runProcess(pb);
|
||||||
|
|
||||||
if ((!outputsOpt.isPresent()) || outputsOpt.get().trim().isEmpty()) {
|
if ((!outputsOpt.isPresent()) || outputsOpt.get().trim().isEmpty()) {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
JSONObject jo = JSON.parseObject(outputsOpt.get());
|
final JSONObject jo = JSON.parseObject(outputsOpt.get());
|
||||||
return Optional.of(Bytes.fromHex(jo.getString("response_sha256_hex")).bytes());
|
return Optional.of(Bytes.fromHex(jo.getString("response_sha256_hex")).bytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Optional<byte[]> decryptPgpEnvelop(String cardCli, String pin, String pgpEnvelop) {
|
public static Optional<byte[]> decryptPgpEnvelop(String cardCli, String pin, String pgpEnvelop) {
|
||||||
ProcessBuilder pb = new ProcessBuilder(
|
final ProcessBuilder pb = new ProcessBuilder(
|
||||||
cardCli,
|
cardCli,
|
||||||
"pgp-card-decrypt",
|
"pgp-card-decrypt",
|
||||||
"--cipher-base64", pgpEnvelop,
|
"--cipher-base64", pgpEnvelop,
|
||||||
"--pin", pin,
|
"--pin", pin,
|
||||||
"--json");
|
"--json");
|
||||||
log.info("Start: " + cardCli);
|
log.info("Start: " + cardCli);
|
||||||
Optional<String> outputsOpt = runProcess(pb);
|
final Optional<String> outputsOpt = runProcess(pb);
|
||||||
if (!outputsOpt.isPresent()) {
|
if (!outputsOpt.isPresent()) {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
JSONObject jo = JSON.parseObject(outputsOpt.get());
|
final JSONObject jo = JSON.parseObject(outputsOpt.get());
|
||||||
return Optional.of(Bytes.fromHex(jo.getString("text_hex")).bytes());
|
return Optional.of(Bytes.fromHex(jo.getString("text_hex")).bytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +66,7 @@ public class CardCliUtil {
|
|||||||
try {
|
try {
|
||||||
log.debug("Start process: " + pb.command());
|
log.debug("Start process: " + pb.command());
|
||||||
p = pb.start();
|
p = pb.start();
|
||||||
int ret = p.waitFor();
|
final int ret = p.waitFor();
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
log.info("Finished command, ret code: " + ret);
|
log.info("Finished command, ret code: " + ret);
|
||||||
} else {
|
} else {
|
||||||
@@ -74,13 +74,13 @@ public class CardCliUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (log.isDebugEnable()) {
|
if (log.isDebugEnable()) {
|
||||||
byte[] errorBytes = IOUtil.readToBytes(p.getErrorStream());
|
final byte[] errorBytes = IOUtil.readToBytes(p.getErrorStream());
|
||||||
String errorOutputs = new String(errorBytes, StandardCharsets.UTF_8);
|
final String errorOutputs = new String(errorBytes, StandardCharsets.UTF_8);
|
||||||
log.debug("Read cmd error outputs: [[[~" + errorOutputs + "~]]]");
|
log.debug("Read cmd error outputs: [[[~" + errorOutputs + "~]]]");
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] jsonBytes = IOUtil.readToBytes(p.getInputStream());
|
final byte[] jsonBytes = IOUtil.readToBytes(p.getInputStream());
|
||||||
String outputs = new String(jsonBytes, StandardCharsets.UTF_8);
|
final String outputs = new String(jsonBytes, StandardCharsets.UTF_8);
|
||||||
if (log.isDebugEnable()) {
|
if (log.isDebugEnable()) {
|
||||||
log.debug("Read cmd outputs: [[[~" + outputs + "~]]]");
|
log.debug("Read cmd outputs: [[[~" + outputs + "~]]]");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,13 +13,13 @@ public class MacDockerHelper {
|
|||||||
static {
|
static {
|
||||||
if (ClassLoaderUtil.isClassCanBeLoad(COM_APPLE_EAWT_APPLICATION)) {
|
if (ClassLoaderUtil.isClassCanBeLoad(COM_APPLE_EAWT_APPLICATION)) {
|
||||||
try {
|
try {
|
||||||
Class<?> comAppleEawtApplication = ClassLoaderUtil.loadClass(COM_APPLE_EAWT_APPLICATION);
|
final Class<?> comAppleEawtApplication = ClassLoaderUtil.loadClass(COM_APPLE_EAWT_APPLICATION);
|
||||||
Method getApplicationMetohd = ReflectUtil.getDeclaredMethod(comAppleEawtApplication, "getApplication", new Class[0]);
|
final Method getApplicationMetohd = ReflectUtil.getDeclaredMethod(comAppleEawtApplication, "getApplication", new Class[0]);
|
||||||
//noinspection RedundantArrayCreation
|
//noinspection RedundantArrayCreation
|
||||||
Object application = ReflectUtil.invokeMethod(getApplicationMetohd, null, new Object[0]);
|
final Object application = ReflectUtil.invokeMethod(getApplicationMetohd, null, new Object[0]);
|
||||||
byte[] iconBytes = RResource.from(SwingWindow.class.getClassLoader()).rStream("icon.png").bytesAndClose();
|
final byte[] iconBytes = RResource.from(SwingWindow.class.getClassLoader()).rStream("icon.png").bytesAndClose();
|
||||||
Image image = Toolkit.getDefaultToolkit().createImage(iconBytes);
|
final Image image = Toolkit.getDefaultToolkit().createImage(iconBytes);
|
||||||
Method setDockIconImageMethod = ReflectUtil.getDeclaredMethod(comAppleEawtApplication, "setDockIconImage", new Class[]{Image.class});
|
final Method setDockIconImageMethod = ReflectUtil.getDeclaredMethod(comAppleEawtApplication, "setDockIconImage", new Class[]{Image.class});
|
||||||
//noinspection RedundantArrayCreation
|
//noinspection RedundantArrayCreation
|
||||||
ReflectUtil.invokeMethod(setDockIconImageMethod, application, new Object[]{image});
|
ReflectUtil.invokeMethod(setDockIconImageMethod, application, new Object[]{image});
|
||||||
} catch (Error e) {
|
} catch (Error e) {
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ public class SwingWindow {
|
|||||||
|
|
||||||
public SwingWindow show() {
|
public SwingWindow show() {
|
||||||
countDownLatch = new CountDownLatch(1);
|
countDownLatch = new CountDownLatch(1);
|
||||||
JFrame frame = new JFrame((StringUtil.isEmpty(title) ? "" : (title + " - ")) + "Tiny Encrypt Window");
|
final JFrame frame = new JFrame((StringUtil.isEmpty(title) ? "" : (title + " - ")) + "Tiny Encrypt Window");
|
||||||
frame.addWindowListener(new WindowListenerImpl() {
|
frame.addWindowListener(new WindowListenerImpl() {
|
||||||
@Override
|
@Override
|
||||||
public void windowClosing(WindowEvent e) {
|
public void windowClosing(WindowEvent e) {
|
||||||
@@ -71,12 +71,12 @@ public class SwingWindow {
|
|||||||
countDownLatch.countDown();
|
countDownLatch.countDown();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
JTextArea text = new JTextArea(StringUtil.def(this.text, ""), 30, 80);
|
final JTextArea text = new JTextArea(StringUtil.def(this.text, ""), 30, 80);
|
||||||
text.setWrapStyleWord(true);
|
text.setWrapStyleWord(true);
|
||||||
text.setLineWrap(true);
|
text.setLineWrap(true);
|
||||||
text.setEditable(editable);
|
text.setEditable(editable);
|
||||||
JScrollPane textScrollPane = new JScrollPane(text);
|
final JScrollPane textScrollPane = new JScrollPane(text);
|
||||||
JLabel label = new JLabel(StringUtil.def(message, "Tiny Encrypt default message."));
|
final JLabel label = new JLabel(StringUtil.def(message, "Tiny Encrypt default message."));
|
||||||
JButton btnOk = null;
|
JButton btnOk = null;
|
||||||
if (editable) {
|
if (editable) {
|
||||||
btnOk = new JButton("OK!");
|
btnOk = new JButton("OK!");
|
||||||
@@ -88,13 +88,13 @@ public class SwingWindow {
|
|||||||
countDownLatch.countDown();
|
countDownLatch.countDown();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
JButton btnCancel = new JButton("Cancel");
|
final JButton btnCancel = new JButton("Cancel");
|
||||||
btnCancel.addActionListener((e) -> {
|
btnCancel.addActionListener((e) -> {
|
||||||
frame.setVisible(false);
|
frame.setVisible(false);
|
||||||
frame.dispose();
|
frame.dispose();
|
||||||
countDownLatch.countDown();
|
countDownLatch.countDown();
|
||||||
});
|
});
|
||||||
JPanel pane = new JPanel();
|
final JPanel pane = new JPanel();
|
||||||
if (btnOk != null) {
|
if (btnOk != null) {
|
||||||
pane.add(btnOk);
|
pane.add(btnOk);
|
||||||
}
|
}
|
||||||
@@ -106,7 +106,7 @@ public class SwingWindow {
|
|||||||
|
|
||||||
frame.pack();
|
frame.pack();
|
||||||
|
|
||||||
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
|
final Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
|
||||||
frame.setLocation(
|
frame.setLocation(
|
||||||
(dim.width / 2) - (frame.getSize().width / 2),
|
(dim.width / 2) - (frame.getSize().width / 2),
|
||||||
(dim.height / 2) - (frame.getSize().height / 2)
|
(dim.height / 2) - (frame.getSize().height / 2)
|
||||||
|
|||||||
Reference in New Issue
Block a user