ensure config, wallet dirs and wallets are owner read/write only

This commit is contained in:
Craig Raw 2021-05-05 11:25:25 +02:00
parent 438c13fe2d
commit a0d3f3b745
3 changed files with 73 additions and 17 deletions

View file

@ -936,8 +936,13 @@ public class AppController implements Initializable {
Optional<SecureString> password = dlg.showAndWait(); Optional<SecureString> password = dlg.showAndWait();
if(password.isPresent()) { if(password.isPresent()) {
if(password.get().length() == 0) { if(password.get().length() == 0) {
try {
storage.setEncryptionPubKey(Storage.NO_PASSWORD_KEY); storage.setEncryptionPubKey(Storage.NO_PASSWORD_KEY);
storage.storeWallet(wallet);
addWalletTabOrWindow(storage, wallet, null, false); addWalletTabOrWindow(storage, wallet, null, false);
} catch(IOException e) {
log.error("Error saving imported wallet", e);
}
} else { } else {
Storage.KeyDerivationService keyDerivationService = new Storage.KeyDerivationService(storage, password.get()); Storage.KeyDerivationService keyDerivationService = new Storage.KeyDerivationService(storage, password.get());
keyDerivationService.setOnSucceeded(workerStateEvent -> { keyDerivationService.setOnSucceeded(workerStateEvent -> {
@ -950,7 +955,10 @@ public class AppController implements Initializable {
key = new Key(encryptionFullKey.getPrivKeyBytes(), storage.getKeyDeriver().getSalt(), EncryptionType.Deriver.ARGON2); key = new Key(encryptionFullKey.getPrivKeyBytes(), storage.getKeyDeriver().getSalt(), EncryptionType.Deriver.ARGON2);
wallet.encrypt(key); wallet.encrypt(key);
storage.setEncryptionPubKey(encryptionPubKey); storage.setEncryptionPubKey(encryptionPubKey);
storage.storeWallet(wallet);
addWalletTabOrWindow(storage, wallet, null, false); addWalletTabOrWindow(storage, wallet, null, false);
} catch(IOException e) {
log.error("Error saving imported wallet", e);
} finally { } finally {
encryptionFullKey.clear(); encryptionFullKey.clear();
if(key != null) { if(key != null) {

View file

@ -11,6 +11,8 @@ import org.slf4j.LoggerFactory;
import java.io.*; import java.io.*;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.nio.file.Files;
import java.nio.file.attribute.PosixFilePermissions;
import java.util.Arrays; import java.util.Arrays;
import java.util.Currency; import java.util.Currency;
import java.util.List; import java.util.List;
@ -67,10 +69,6 @@ public class Config {
private static File getConfigFile() { private static File getConfigFile() {
File sparrowDir = Storage.getSparrowDir(); File sparrowDir = Storage.getSparrowDir();
if(!sparrowDir.exists()) {
sparrowDir.mkdirs();
}
return new File(sparrowDir, CONFIG_FILENAME); return new File(sparrowDir, CONFIG_FILENAME);
} }
@ -445,6 +443,10 @@ public class Config {
Gson gson = getGson(); Gson gson = getGson();
try { try {
File configFile = getConfigFile(); File configFile = getConfigFile();
if(!configFile.exists()) {
Files.createFile(configFile.toPath(), PosixFilePermissions.asFileAttribute(Storage.getFileOwnerOnlyFilePermissions()));
}
Writer writer = new FileWriter(configFile); Writer writer = new FileWriter(configFile);
gson.toJson(this, writer); gson.toJson(this, writer);
writer.flush(); writer.flush();

View file

@ -1,6 +1,5 @@
package com.sparrowwallet.sparrow.io; package com.sparrowwallet.sparrow.io;
import com.google.common.io.Files;
import com.google.gson.*; import com.google.gson.*;
import com.sparrowwallet.drongo.ExtendedKey; import com.sparrowwallet.drongo.ExtendedKey;
import com.sparrowwallet.drongo.Network; import com.sparrowwallet.drongo.Network;
@ -23,6 +22,9 @@ import java.io.*;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets; 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.SecureRandom;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateEncodingException;
@ -153,7 +155,7 @@ public class Storage {
} }
File parent = walletFile.getParentFile(); File parent = walletFile.getParentFile();
if(!parent.exists() && !parent.mkdirs()) { if(!parent.exists() && !createOwnerOnlyDirectory(parent)) {
throw new IOException("Could not create folder " + parent); throw new IOException("Could not create folder " + parent);
} }
@ -167,6 +169,10 @@ public class Storage {
walletFile = jsonFile; walletFile = jsonFile;
} }
if(!walletFile.exists()) {
Files.createFile(walletFile.toPath(), PosixFilePermissions.asFileAttribute(getFileOwnerOnlyFilePermissions()));
}
Writer writer = new FileWriter(walletFile); Writer writer = new FileWriter(walletFile);
gson.toJson(wallet, writer); gson.toJson(wallet, writer);
writer.close(); writer.close();
@ -174,7 +180,7 @@ public class Storage {
private void storeWallet(ECKey encryptionPubKey, Wallet wallet) throws IOException { private void storeWallet(ECKey encryptionPubKey, Wallet wallet) throws IOException {
File parent = walletFile.getParentFile(); File parent = walletFile.getParentFile();
if(!parent.exists() && !parent.mkdirs()) { if(!parent.exists() && !createOwnerOnlyDirectory(parent)) {
throw new IOException("Could not create folder " + parent); throw new IOException("Could not create folder " + parent);
} }
@ -188,6 +194,10 @@ public class Storage {
walletFile = noJsonFile; walletFile = noJsonFile;
} }
if(!walletFile.exists()) {
Files.createFile(walletFile.toPath(), PosixFilePermissions.asFileAttribute(getFileOwnerOnlyFilePermissions()));
}
OutputStream outputStream = new FileOutputStream(walletFile); OutputStream outputStream = new FileOutputStream(walletFile);
writeBinaryHeader(outputStream); writeBinaryHeader(outputStream);
@ -238,7 +248,10 @@ public class Storage {
} }
File backupFile = new File(backupDir, backupName); 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() { public void deleteBackups() {
@ -259,7 +272,7 @@ public class Storage {
private File[] getBackups(String extension, String notExtension) { private File[] getBackups(String extension, String notExtension) {
File backupDir = getWalletsBackupDir(); File backupDir = getWalletsBackupDir();
File[] backups = backupDir.listFiles((dir, name) -> { 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 && getBackupDate(name) != null &&
(extension == null || name.endsWith("." + extension)) && (extension == null || name.endsWith("." + extension)) &&
(notExtension == null || !name.endsWith("." + notExtension)); (notExtension == null || !name.endsWith("." + notExtension));
@ -372,7 +385,7 @@ public class Storage {
public static File getWalletsBackupDir() { public static File getWalletsBackupDir() {
File walletsBackupDir = new File(getWalletsDir(), WALLETS_BACKUP_DIR); File walletsBackupDir = new File(getWalletsDir(), WALLETS_BACKUP_DIR);
if(!walletsBackupDir.exists()) { if(!walletsBackupDir.exists()) {
walletsBackupDir.mkdirs(); createOwnerOnlyDirectory(walletsBackupDir);
} }
return walletsBackupDir; return walletsBackupDir;
@ -381,7 +394,7 @@ public class Storage {
public static File getWalletsDir() { public static File getWalletsDir() {
File walletsDir = new File(getSparrowDir(), WALLETS_DIR); File walletsDir = new File(getSparrowDir(), WALLETS_DIR);
if(!walletsDir.exists()) { if(!walletsDir.exists()) {
walletsDir.mkdirs(); createOwnerOnlyDirectory(walletsDir);
} }
return walletsDir; return walletsDir;
@ -390,7 +403,7 @@ public class Storage {
public static File getCertificateFile(String host) { public static File getCertificateFile(String host) {
File certsDir = getCertsDir(); File certsDir = getCertsDir();
File[] certs = certsDir.listFiles((dir, name) -> name.equals(host)); File[] certs = certsDir.listFiles((dir, name) -> name.equals(host));
if(certs.length > 0) { if(certs != null && certs.length > 0) {
return certs[0]; return certs[0];
} }
@ -412,18 +425,25 @@ public class Storage {
static File getCertsDir() { static File getCertsDir() {
File certsDir = new File(getSparrowDir(), CERTS_DIR); File certsDir = new File(getSparrowDir(), CERTS_DIR);
if(!certsDir.exists()) { if(!certsDir.exists()) {
certsDir.mkdirs(); createOwnerOnlyDirectory(certsDir);
} }
return certsDir; return certsDir;
} }
static File getSparrowDir() { static File getSparrowDir() {
File sparrowDir;
if(Network.get() != Network.MAINNET) { 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() { public static File getSparrowHome() {
@ -446,6 +466,32 @@ public class Storage {
return new File(System.getProperty("user.home")); 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<PosixFilePermission> getDirectoryOwnerOnlyFilePermissions() {
Set<PosixFilePermission> ownerOnly = getFileOwnerOnlyFilePermissions();
ownerOnly.add(PosixFilePermission.OWNER_EXECUTE);
return ownerOnly;
}
public static Set<PosixFilePermission> getFileOwnerOnlyFilePermissions() {
Set<PosixFilePermission> ownerOnly = EnumSet.noneOf(PosixFilePermission.class);
ownerOnly.add(PosixFilePermission.OWNER_READ);
ownerOnly.add(PosixFilePermission.OWNER_WRITE);
return ownerOnly;
}
private static class ExtendedPublicKeySerializer implements JsonSerializer<ExtendedKey> { private static class ExtendedPublicKeySerializer implements JsonSerializer<ExtendedKey> {
@Override @Override
public JsonElement serialize(ExtendedKey src, Type typeOfSrc, JsonSerializationContext context) { public JsonElement serialize(ExtendedKey src, Type typeOfSrc, JsonSerializationContext context) {