From a0d3f3b745cc4ea8b680ad1160cf64f8ec00e11d Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Wed, 5 May 2021 11:25:25 +0200 Subject: [PATCH] ensure config, wallet dirs and wallets are owner read/write only --- .../sparrowwallet/sparrow/AppController.java | 12 +++- .../com/sparrowwallet/sparrow/io/Config.java | 10 +-- .../com/sparrowwallet/sparrow/io/Storage.java | 68 ++++++++++++++++--- 3 files changed, 73 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/sparrowwallet/sparrow/AppController.java b/src/main/java/com/sparrowwallet/sparrow/AppController.java index 5107df56..87c3a40b 100644 --- a/src/main/java/com/sparrowwallet/sparrow/AppController.java +++ b/src/main/java/com/sparrowwallet/sparrow/AppController.java @@ -936,8 +936,13 @@ public class AppController implements Initializable { Optional password = dlg.showAndWait(); if(password.isPresent()) { if(password.get().length() == 0) { - storage.setEncryptionPubKey(Storage.NO_PASSWORD_KEY); - addWalletTabOrWindow(storage, wallet, null, false); + try { + storage.setEncryptionPubKey(Storage.NO_PASSWORD_KEY); + storage.storeWallet(wallet); + addWalletTabOrWindow(storage, wallet, null, false); + } catch(IOException e) { + log.error("Error saving imported wallet", e); + } } else { Storage.KeyDerivationService keyDerivationService = new Storage.KeyDerivationService(storage, password.get()); keyDerivationService.setOnSucceeded(workerStateEvent -> { @@ -950,7 +955,10 @@ public class AppController implements Initializable { key = new Key(encryptionFullKey.getPrivKeyBytes(), storage.getKeyDeriver().getSalt(), EncryptionType.Deriver.ARGON2); wallet.encrypt(key); storage.setEncryptionPubKey(encryptionPubKey); + storage.storeWallet(wallet); addWalletTabOrWindow(storage, wallet, null, false); + } catch(IOException e) { + log.error("Error saving imported wallet", e); } finally { encryptionFullKey.clear(); if(key != null) { diff --git a/src/main/java/com/sparrowwallet/sparrow/io/Config.java b/src/main/java/com/sparrowwallet/sparrow/io/Config.java index 93bfce03..a4e39b49 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/Config.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/Config.java @@ -11,6 +11,8 @@ import org.slf4j.LoggerFactory; import java.io.*; import java.lang.reflect.Type; +import java.nio.file.Files; +import java.nio.file.attribute.PosixFilePermissions; import java.util.Arrays; import java.util.Currency; import java.util.List; @@ -67,10 +69,6 @@ public class Config { private static File getConfigFile() { File sparrowDir = Storage.getSparrowDir(); - if(!sparrowDir.exists()) { - sparrowDir.mkdirs(); - } - return new File(sparrowDir, CONFIG_FILENAME); } @@ -445,6 +443,10 @@ public class Config { Gson gson = getGson(); try { File configFile = getConfigFile(); + if(!configFile.exists()) { + Files.createFile(configFile.toPath(), PosixFilePermissions.asFileAttribute(Storage.getFileOwnerOnlyFilePermissions())); + } + Writer writer = new FileWriter(configFile); gson.toJson(this, writer); writer.flush(); diff --git a/src/main/java/com/sparrowwallet/sparrow/io/Storage.java b/src/main/java/com/sparrowwallet/sparrow/io/Storage.java index 15242f00..ed6efd3e 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/Storage.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/Storage.java @@ -1,6 +1,5 @@ package com.sparrowwallet.sparrow.io; -import com.google.common.io.Files; import com.google.gson.*; import com.sparrowwallet.drongo.ExtendedKey; import com.sparrowwallet.drongo.Network; @@ -23,6 +22,9 @@ import java.io.*; import java.lang.reflect.Type; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.attribute.PosixFilePermission; +import java.nio.file.attribute.PosixFilePermissions; import java.security.SecureRandom; import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; @@ -153,7 +155,7 @@ public class Storage { } File parent = walletFile.getParentFile(); - if(!parent.exists() && !parent.mkdirs()) { + if(!parent.exists() && !createOwnerOnlyDirectory(parent)) { throw new IOException("Could not create folder " + parent); } @@ -167,6 +169,10 @@ public class Storage { walletFile = jsonFile; } + if(!walletFile.exists()) { + Files.createFile(walletFile.toPath(), PosixFilePermissions.asFileAttribute(getFileOwnerOnlyFilePermissions())); + } + Writer writer = new FileWriter(walletFile); gson.toJson(wallet, writer); writer.close(); @@ -174,7 +180,7 @@ public class Storage { private void storeWallet(ECKey encryptionPubKey, Wallet wallet) throws IOException { File parent = walletFile.getParentFile(); - if(!parent.exists() && !parent.mkdirs()) { + if(!parent.exists() && !createOwnerOnlyDirectory(parent)) { throw new IOException("Could not create folder " + parent); } @@ -188,6 +194,10 @@ public class Storage { walletFile = noJsonFile; } + if(!walletFile.exists()) { + Files.createFile(walletFile.toPath(), PosixFilePermissions.asFileAttribute(getFileOwnerOnlyFilePermissions())); + } + OutputStream outputStream = new FileOutputStream(walletFile); writeBinaryHeader(outputStream); @@ -238,7 +248,10 @@ public class Storage { } File backupFile = new File(backupDir, backupName); - Files.copy(walletFile, backupFile); + if(!backupFile.exists()) { + Files.createFile(backupFile.toPath(), PosixFilePermissions.asFileAttribute(getFileOwnerOnlyFilePermissions())); + } + com.google.common.io.Files.copy(walletFile, backupFile); } public void deleteBackups() { @@ -259,7 +272,7 @@ public class Storage { private File[] getBackups(String extension, String notExtension) { File backupDir = getWalletsBackupDir(); File[] backups = backupDir.listFiles((dir, name) -> { - return name.startsWith(Files.getNameWithoutExtension(walletFile.getName()) + "-") && + return name.startsWith(com.google.common.io.Files.getNameWithoutExtension(walletFile.getName()) + "-") && getBackupDate(name) != null && (extension == null || name.endsWith("." + extension)) && (notExtension == null || !name.endsWith("." + notExtension)); @@ -372,7 +385,7 @@ public class Storage { public static File getWalletsBackupDir() { File walletsBackupDir = new File(getWalletsDir(), WALLETS_BACKUP_DIR); if(!walletsBackupDir.exists()) { - walletsBackupDir.mkdirs(); + createOwnerOnlyDirectory(walletsBackupDir); } return walletsBackupDir; @@ -381,7 +394,7 @@ public class Storage { public static File getWalletsDir() { File walletsDir = new File(getSparrowDir(), WALLETS_DIR); if(!walletsDir.exists()) { - walletsDir.mkdirs(); + createOwnerOnlyDirectory(walletsDir); } return walletsDir; @@ -390,7 +403,7 @@ public class Storage { public static File getCertificateFile(String host) { File certsDir = getCertsDir(); File[] certs = certsDir.listFiles((dir, name) -> name.equals(host)); - if(certs.length > 0) { + if(certs != null && certs.length > 0) { return certs[0]; } @@ -412,18 +425,25 @@ public class Storage { static File getCertsDir() { File certsDir = new File(getSparrowDir(), CERTS_DIR); if(!certsDir.exists()) { - certsDir.mkdirs(); + createOwnerOnlyDirectory(certsDir); } return certsDir; } static File getSparrowDir() { + File sparrowDir; if(Network.get() != Network.MAINNET) { - return new File(getSparrowHome(), Network.get().getName()); + sparrowDir = new File(getSparrowHome(), Network.get().getName()); + } else { + sparrowDir = getSparrowHome(); } - return getSparrowHome(); + if(!sparrowDir.exists()) { + createOwnerOnlyDirectory(sparrowDir); + } + + return sparrowDir; } public static File getSparrowHome() { @@ -446,6 +466,32 @@ public class Storage { return new File(System.getProperty("user.home")); } + private static boolean createOwnerOnlyDirectory(File directory) { + try { + Files.createDirectories(directory.toPath(), PosixFilePermissions.asFileAttribute(getDirectoryOwnerOnlyFilePermissions())); + return true; + } catch(IOException e) { + log.error("Could not create directory " + directory.getAbsolutePath(), e); + } + + return false; + } + + public static Set getDirectoryOwnerOnlyFilePermissions() { + Set ownerOnly = getFileOwnerOnlyFilePermissions(); + ownerOnly.add(PosixFilePermission.OWNER_EXECUTE); + + return ownerOnly; + } + + public static Set getFileOwnerOnlyFilePermissions() { + Set ownerOnly = EnumSet.noneOf(PosixFilePermission.class); + ownerOnly.add(PosixFilePermission.OWNER_READ); + ownerOnly.add(PosixFilePermission.OWNER_WRITE); + + return ownerOnly; + } + private static class ExtendedPublicKeySerializer implements JsonSerializer { @Override public JsonElement serialize(ExtendedKey src, Type typeOfSrc, JsonSerializationContext context) {