package org.ripple.power.database.secrecy; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; import org.ripple.power.utils.ByteUtils; import org.ripple.power.wallet.Passphrase; public final class SecureDataBase { private final Passphrase passphrase; private final File dbPath; private static final String SECURE_INDEX = "SECURE_INDEX"; public SecureDataBase(File file) { this.dbPath = file; this.passphrase = new Passphrase(); this.ensureFile(); } public SecureDataBase(String path) { this.dbPath = new File(path); this.passphrase = new Passphrase(); this.ensureFile(); } private void ensureFile() { File dbFile = this.dbPath; if (!dbFile.exists()) { try { dbFile.createNewFile(); } catch (IOException ex) { ex.printStackTrace(); } } } public void clear() { File dbFile = this.dbFile(); if (dbFile.exists()) { dbFile.delete(); } ensureFile(); } public void lock() { this.passphrase.clear(); } public boolean isLocked() { return this.passphrase.isClear(); } public void setPassphrase(String passphrase) throws Exception { this.passphrase.setPassphrase(passphrase); if (dbFile().length() == 0) { return; } try { this.getMasterIndex(); } catch (Exception ex) { lock(); ex.printStackTrace(); } } private File dbFile() { ensureFile(); return this.dbPath; } private ZipOutputStream outZip() throws FileNotFoundException { return new ZipOutputStream(new BufferedOutputStream( new FileOutputStream(dbFile()))); } private ZipFile zipDbFile() throws IOException { return new ZipFile(dbFile()); } public boolean isEmpty() { return (dbFile().length() < 1L); } public SecureIndex getMasterIndex() throws Exception { try (ZipFile zipFile = zipDbFile(); InputStream masterIndexInStream = zipFile .getInputStream(zipFile.getEntry(SECURE_INDEX));) { byte[] encryptedMasterIndex = ByteUtils .readFully(masterIndexInStream); byte[] decryptedMasterIndex = Passphrase.decrypt(this.passphrase, encryptedMasterIndex); return Serialization.<SecureIndex> inflate(decryptedMasterIndex); } catch (IOException | ClassNotFoundException ex) { ex.printStackTrace(); } return null; } public void commitMasterIndex(SecureIndex masterIndex) throws Exception { try (ZipOutputStream zipOut = outZip();) { for (BaseTable fileTable : masterIndex.getFileTables()) { for (BaseTableEntry fileTableEntry : fileTable.getAll()) { if (!fileTableEntry.isSourceAttached()) { continue; } zipOut.putNextEntry(new ZipEntry(fileTableEntry .getFileNameHash())); Path sourceFilePath = fileTableEntry.getSourceFilePath(); byte[] fileBytes = ByteUtils.readFully(sourceFilePath); zipOut.write(Passphrase.encrypt(this.passphrase, fileBytes)); zipOut.flush(); zipOut.closeEntry(); fileTableEntry.detachSource(); } } masterIndex.incrementCommitCount(); byte[] encryptedMasterIndex = Passphrase.encrypt(this.passphrase, Serialization.<SecureIndex> deflate(masterIndex)); zipOut.putNextEntry(new ZipEntry(SECURE_INDEX)); zipOut.write(encryptedMasterIndex); zipOut.flush(); zipOut.closeEntry(); zipOut.close(); } catch (IOException ex) { ex.printStackTrace(); } } public byte[] loadFile(BaseTableEntry fileTableEntry) throws Exception { if (fileTableEntry == null) { return null; } byte[] fileBytes = null; ensureFile(); try { if (Files.size(dbFile().toPath()) < 1L) { return fileBytes; } } catch (IOException ex) { throw ex; } byte[] encryptedFile; try (ZipFile zipFile = zipDbFile(); InputStream fileInStream = zipFile.getInputStream(zipFile .getEntry(fileTableEntry.getFileNameHash()));) { encryptedFile = ByteUtils.readFully(fileInStream); } fileBytes = Passphrase.decrypt(this.passphrase, encryptedFile); return fileBytes; } }