Skip to content

Commit

Permalink
Correct protection of default fields #51 and tidy
Browse files Browse the repository at this point in the history
  • Loading branch information
jorabin committed Aug 24, 2023
1 parent e2d7464 commit 7cb4488
Showing 1 changed file with 72 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,19 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamWriter;

import com.fasterxml.jackson.databind.MapperFeature;
import org.jetbrains.annotations.NotNull;
import org.linguafranca.pwdb.Entry;
import org.linguafranca.pwdb.SerializableDatabase;
import org.linguafranca.pwdb.kdbx.Helpers;
import org.linguafranca.pwdb.kdbx.jackson.converter.ValueDeserialized;
import org.linguafranca.pwdb.kdbx.jackson.converter.ValueDeserializer;
import org.linguafranca.pwdb.kdbx.jackson.converter.ValueSerializer;
import org.linguafranca.pwdb.kdbx.jackson.model.EntryClasses;
import org.linguafranca.pwdb.kdbx.jackson.model.KeePassFile;
Expand All @@ -41,6 +46,8 @@
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;

import static org.linguafranca.pwdb.Entry.STANDARD_PROPERTY_NAME_TITLE;

public class JacksonSerializableDatabase implements SerializableDatabase {

public KeePassFile keePassFile;
Expand All @@ -67,7 +74,7 @@ public JacksonSerializableDatabase(KeePassFile keePassFile) {
public JacksonSerializableDatabase load(InputStream inputStream) throws IOException {
XmlMapper mapper = new XmlMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(EntryClasses.StringProperty.Value.class, new ValueDeserialized(encryptor));
module.addDeserializer(EntryClasses.StringProperty.Value.class, new ValueDeserializer(encryptor));
mapper.registerModule(module);
keePassFile = mapper.readValue(inputStream, KeePassFile.class);
return this;
Expand All @@ -76,35 +83,88 @@ public JacksonSerializableDatabase load(InputStream inputStream) throws IOExcept

@Override
public void save(OutputStream outputStream) throws IOException {

prepareForSave(keePassFile.root.group);
try {

XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newFactory();
XmlMapper mapper = new XmlMapper();

SimpleModule module = new SimpleModule();
module.addSerializer(EntryClasses.StringProperty.Value.class, new ValueSerializer(encryptor));
// disable auto-detection, only use annotated values
XmlMapper mapper = XmlMapper.builder()
.disable(MapperFeature.AUTO_DETECT_CREATORS,
MapperFeature.AUTO_DETECT_FIELDS,
MapperFeature.AUTO_DETECT_GETTERS,
MapperFeature.AUTO_DETECT_SETTERS,
MapperFeature.AUTO_DETECT_IS_GETTERS)
.build();
mapper.registerModule(module);
mapper.enable(ToXmlGenerator.Feature.WRITE_XML_DECLARATION);
mapper.enable(SerializationFeature.INDENT_OUTPUT);
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);

// set the serializer to Woodstox
System.setProperty("javax.xml.stream.XMLOutputFactory", "com.ctc.wstx.stax.WstxOutputFactory");
XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newFactory();
xmlOutputFactory.setProperty(WstxOutputProperties.P_USE_DOUBLE_QUOTES_IN_XML_DECL, true);
xmlOutputFactory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, false);
xmlOutputFactory.setProperty(WstxInputProperties.P_RETURN_NULL_FOR_DEFAULT_NAMESPACE, true);

OutputStreamWriter osw = new OutputStreamWriter(outputStream);
XMLStreamWriter sw = xmlOutputFactory.createXMLStreamWriter(osw);
sw.setPrefix("xml", "http://www.w3.org/XML/1998/namespace");
try {
sw.setPrefix("xml", "http://www.w3.org/XML/1998/namespace");

mapper.writeValue(sw, keePassFile);

sw.writeEndDocument();
sw.close();
mapper.writeValue(sw, keePassFile);

sw.writeEndDocument();
} finally {
sw.close();
osw.close();
}

} catch(Exception e) {
throw new IllegalStateException(e);
}
}


/**
* Create a list of names of properties that should be encrypted by default
*/
@NotNull
private List<String> getToEncrypt() {
final List<String> toEncrypt = new ArrayList<>();
for (String propertyName: Entry.STANDARD_PROPERTY_NAMES) {
if (keePassFile.meta.memoryProtection.shouldProtect(propertyName)) {
toEncrypt.add(propertyName);
}
}
return toEncrypt;
}

/**
* Utility to mark fields that need to be encrypted and vice versa
*
* @param parent the group to start from
*/
private static void prepareForSave(JacksonGroup parent){
for (JacksonGroup group: parent.groups) {
prepareForSave(group);
}
for (JacksonEntry entry: parent.entries) {
for (EntryClasses.StringProperty property : entry.string) {
boolean shouldProtect = parent.database.shouldProtect(property.getKey());
property.getValue().setProtectOnOutput(shouldProtect || property.getValue().getProtectOnOutput());
}
if (Objects.nonNull(entry.history)) {
for (JacksonEntry entry2 : entry.history.getEntry()) {
for (EntryClasses.StringProperty property : entry2.string) {
boolean shouldProtect = parent.database.shouldProtect(property.getKey());
property.getValue().setProtectOnOutput(shouldProtect || property.getValue().getProtectOnOutput());
}
}
}
}
}

@Override
public byte[] getHeaderHash() {
return keePassFile.meta.headerHash;
Expand Down

0 comments on commit 7cb4488

Please sign in to comment.