mirror of
https://codeberg.org/Mercury-IM/Mercury-IM
synced 2024-09-26 01:39:35 +02:00
Prototype ikey store implementation
This commit is contained in:
parent
1d4e729f4c
commit
466eb6f228
|
@ -0,0 +1,70 @@
|
||||||
|
package org.jivesoftware.smackx.ikey;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.parsing.SmackParsingException;
|
||||||
|
import org.jivesoftware.smack.test.util.TestUtils;
|
||||||
|
import org.jivesoftware.smack.util.Objects;
|
||||||
|
import org.jivesoftware.smack.xml.XmlPullParserException;
|
||||||
|
import org.jivesoftware.smackx.ikey.element.IkeyElement;
|
||||||
|
import org.jivesoftware.smackx.ikey.provider.IkeyElementProvider;
|
||||||
|
import org.jxmpp.jid.EntityBareJid;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public class FileBasedIkeyStore implements IkeyStore {
|
||||||
|
|
||||||
|
private final File baseFile;
|
||||||
|
|
||||||
|
public FileBasedIkeyStore(File file) {
|
||||||
|
this.baseFile = Objects.requireNonNull(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IkeyElement loadIkeyRecord(EntityBareJid jid) throws IOException {
|
||||||
|
File file = new File(baseFile, jid.asUrlEncodedString());
|
||||||
|
if (file.exists() && !file.isDirectory()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
String content = getFileContent(new FileInputStream(file));
|
||||||
|
return IkeyElementProvider.INSTANCE.parse(TestUtils.getParser(content));
|
||||||
|
} catch (XmlPullParserException | SmackParsingException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void storeIkeyRecord(EntityBareJid jid, IkeyElement record) throws IOException {
|
||||||
|
File file = new File(baseFile, jid.asUrlEncodedString());
|
||||||
|
if (!file.exists()) {
|
||||||
|
file.createNewFile();
|
||||||
|
}
|
||||||
|
writeToFile(new FileOutputStream(file), record.toXML().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getFileContent(FileInputStream fis) throws IOException {
|
||||||
|
try (BufferedReader br = new BufferedReader(new InputStreamReader(fis, StandardCharsets.UTF_8))) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
String line;
|
||||||
|
while((line = br.readLine()) != null) {
|
||||||
|
sb.append(line);
|
||||||
|
sb.append('\n');
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void writeToFile(FileOutputStream fos, String content) throws IOException {
|
||||||
|
try (BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(fos, StandardCharsets.UTF_8))) {
|
||||||
|
bw.write(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -31,9 +31,12 @@ import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
public final class IkeyManager extends Manager {
|
public final class IkeyManager extends Manager {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(IkeyManager.class.getName());
|
||||||
private static final Map<XMPPConnection, IkeyManager> INSTANCES = new WeakHashMap<>();
|
private static final Map<XMPPConnection, IkeyManager> INSTANCES = new WeakHashMap<>();
|
||||||
|
|
||||||
private IkeyStore store;
|
private IkeyStore store;
|
||||||
|
@ -88,7 +91,10 @@ public final class IkeyManager extends Manager {
|
||||||
return fetchIkeyElementFrom(pubSubManager);
|
return fetchIkeyElementFrom(pubSubManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IkeyElement fetchIkeyElementFrom(PubSubManager pubSubManager) throws PubSubException.NotALeafNodeException, SmackException.NoResponseException, SmackException.NotConnectedException, InterruptedException, XMPPException.XMPPErrorException, PubSubException.NotAPubSubNodeException {
|
private IkeyElement fetchIkeyElementFrom(PubSubManager pubSubManager)
|
||||||
|
throws PubSubException.NotALeafNodeException, SmackException.NoResponseException,
|
||||||
|
SmackException.NotConnectedException, InterruptedException, XMPPException.XMPPErrorException,
|
||||||
|
PubSubException.NotAPubSubNodeException {
|
||||||
LeafNode node = pubSubManager.getLeafNode(IkeyConstants.IKEY_NODE);
|
LeafNode node = pubSubManager.getLeafNode(IkeyConstants.IKEY_NODE);
|
||||||
List<PayloadItem<IkeyElement>> items = node.getItems(1);
|
List<PayloadItem<IkeyElement>> items = node.getItems(1);
|
||||||
if (items.isEmpty()) {
|
if (items.isEmpty()) {
|
||||||
|
@ -100,16 +106,22 @@ public final class IkeyManager extends Manager {
|
||||||
|
|
||||||
private void processIkeyElement(EntityBareJid from, IkeyElement element)
|
private void processIkeyElement(EntityBareJid from, IkeyElement element)
|
||||||
throws XMLParserException, IOException, CanonicalizationException, UnsupportedSignatureAlgorithmException {
|
throws XMLParserException, IOException, CanonicalizationException, UnsupportedSignatureAlgorithmException {
|
||||||
if (isFromTheFuture(element) || existsSameOrNewerRecord(element)) {
|
if (isFromTheFuture(element)) {
|
||||||
|
LOGGER.log(Level.WARNING, "Received ikey element appears to be from the future: " + element.getSubordinates().getTimestamp());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existsSameOrNewerRecord(element)) {
|
||||||
|
LOGGER.log(Level.WARNING, "There exists this exact, or a newer ikey record in the database for " + from);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!verifyIkeyElement(from, element)) {
|
if (!verifyIkeyElement(from, element)) {
|
||||||
|
LOGGER.log(Level.WARNING, "Invalid signature on ikey element of " + from);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//store.setLatestTimestamp(from, element.getSubordinates().getTimestamp());
|
store.storeIkeyRecord(from, element);
|
||||||
//store.setIkeySubkeys(from, element.getSubordinates().getSubordinates());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean verifyIkeyElement(EntityBareJid from, IkeyElement element)
|
private boolean verifyIkeyElement(EntityBareJid from, IkeyElement element)
|
||||||
|
@ -139,12 +151,12 @@ public final class IkeyManager extends Manager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean existsSameOrNewerRecord(IkeyElement ikeyElement) {
|
private boolean existsSameOrNewerRecord(IkeyElement ikeyElement) {
|
||||||
Date latestTimestamp = store.getLatestTimestamp(ikeyElement.getSubordinates().getJid());
|
IkeyElement existingRecord = store.loadIkeyRecord(ikeyElement.getSubordinates().getJid());
|
||||||
Date eventTimestamp = ikeyElement.getSubordinates().getTimestamp();
|
if (existingRecord == null) {
|
||||||
if (latestTimestamp == null) {
|
|
||||||
// No record at all found.
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
Date latestTimestamp = existingRecord.getSubordinates().getTimestamp();
|
||||||
|
Date eventTimestamp = ikeyElement.getSubordinates().getTimestamp();
|
||||||
return latestTimestamp.equals(eventTimestamp) // same
|
return latestTimestamp.equals(eventTimestamp) // same
|
||||||
|| latestTimestamp.after(eventTimestamp); // newer
|
|| latestTimestamp.after(eventTimestamp); // newer
|
||||||
}
|
}
|
||||||
|
@ -153,12 +165,10 @@ public final class IkeyManager extends Manager {
|
||||||
(from, event, id, carrierMessage) -> Async.go(() -> {
|
(from, event, id, carrierMessage) -> Async.go(() -> {
|
||||||
try {
|
try {
|
||||||
processIkeyElement(from, event);
|
processIkeyElement(from, event);
|
||||||
} catch (XMLParserException e) {
|
} catch (XMLParserException | CanonicalizationException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
} catch (CanonicalizationException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (UnsupportedSignatureAlgorithmException e) {
|
} catch (UnsupportedSignatureAlgorithmException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
package org.jivesoftware.smackx.ikey;
|
package org.jivesoftware.smackx.ikey;
|
||||||
|
|
||||||
|
import org.jivesoftware.smackx.ikey.element.IkeyElement;
|
||||||
import org.jxmpp.jid.EntityBareJid;
|
import org.jxmpp.jid.EntityBareJid;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.io.IOException;
|
||||||
|
|
||||||
public interface IkeyStore {
|
public interface IkeyStore {
|
||||||
|
|
||||||
Date getLatestTimestamp(EntityBareJid jid);
|
IkeyElement loadIkeyRecord(EntityBareJid jid) throws IOException;
|
||||||
|
|
||||||
|
|
||||||
|
void storeIkeyRecord(EntityBareJid jid, IkeyElement record) throws IOException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
package org.jivesoftware.smackx.ikey.provider;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.XmlEnvironment;
|
||||||
|
import org.jivesoftware.smack.parsing.SmackParsingException;
|
||||||
|
import org.jivesoftware.smack.provider.ExtensionElementProvider;
|
||||||
|
import org.jivesoftware.smack.util.ParserUtils;
|
||||||
|
import org.jivesoftware.smack.xml.XmlPullParser;
|
||||||
|
import org.jivesoftware.smack.xml.XmlPullParserException;
|
||||||
|
import org.jivesoftware.smackx.ikey.element.IkeyElement;
|
||||||
|
import org.jivesoftware.smackx.ikey.element.ProofElement;
|
||||||
|
import org.jivesoftware.smackx.ikey.element.SubordinateElement;
|
||||||
|
import org.jivesoftware.smackx.ikey.element.SubordinateListElement;
|
||||||
|
import org.jivesoftware.smackx.ikey.element.SuperordinateElement;
|
||||||
|
import org.jivesoftware.smackx.ikey.mechanism.IkeyType;
|
||||||
|
import org.jxmpp.jid.EntityBareJid;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class IkeyElementProvider extends ExtensionElementProvider<IkeyElement> {
|
||||||
|
|
||||||
|
public static final IkeyElementProvider INSTANCE = new IkeyElementProvider();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IkeyElement parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment)
|
||||||
|
throws XmlPullParserException, IOException, SmackParsingException {
|
||||||
|
String typeString = ParserUtils.getRequiredAttribute(parser, IkeyElement.ELEMENT);
|
||||||
|
IkeyType type = IkeyType.valueOf(typeString);
|
||||||
|
SuperordinateElement superordinate = null;
|
||||||
|
List<SubordinateElement> subordinates = new ArrayList<>();
|
||||||
|
EntityBareJid jid = null;
|
||||||
|
Date timestamp = null;
|
||||||
|
ProofElement proofElement = null;
|
||||||
|
|
||||||
|
while (parser.getDepth() != initialDepth) {
|
||||||
|
switch (parser.nextTag()) {
|
||||||
|
case START_ELEMENT:
|
||||||
|
switch (parser.getName()) {
|
||||||
|
|
||||||
|
case SuperordinateElement.ELEMENT:
|
||||||
|
superordinate = new SuperordinateElement(parser.nextText());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SubordinateListElement.ELEMENT:
|
||||||
|
jid = ParserUtils.getBareJidAttribute(parser);
|
||||||
|
timestamp = ParserUtils.getDateFromXep82String(
|
||||||
|
ParserUtils.getRequiredAttribute(parser, SubordinateListElement.ATTR_STAMP));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SubordinateElement.ELEMENT:
|
||||||
|
String uriString = ParserUtils.getRequiredAttribute(parser, SubordinateElement.ATTR_SUB_URI);
|
||||||
|
URI uri = URI.create(uriString);
|
||||||
|
String fingerprint = ParserUtils.getRequiredAttribute(parser, SubordinateElement.ATTR_SUB_FINGERPRINT);
|
||||||
|
subordinates.add(new SubordinateElement(uri, fingerprint));
|
||||||
|
|
||||||
|
case ProofElement.ELEMENT:
|
||||||
|
proofElement = new ProofElement(parser.nextText());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case END_ELEMENT:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new IkeyElement(type, superordinate, new SubordinateListElement(jid, timestamp, subordinates), proofElement);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,19 +1,26 @@
|
||||||
package org.jivesoftware.smackx.ikey.element;
|
package org.jivesoftware.smackx.ikey.element;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.parsing.SmackParsingException;
|
||||||
|
import org.jivesoftware.smack.test.util.TestUtils;
|
||||||
|
import org.jivesoftware.smack.xml.XmlPullParserException;
|
||||||
import org.jivesoftware.smackx.ikey.mechanism.IkeyType;
|
import org.jivesoftware.smackx.ikey.mechanism.IkeyType;
|
||||||
|
import org.jivesoftware.smackx.ikey.provider.IkeyElementProvider;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.jxmpp.jid.EntityBareJid;
|
import org.jxmpp.jid.EntityBareJid;
|
||||||
import org.jxmpp.jid.impl.JidCreate;
|
import org.jxmpp.jid.impl.JidCreate;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
public class IkeyElementTest {
|
import static junit.framework.TestCase.assertEquals;
|
||||||
|
|
||||||
|
public class IkeyElementTest extends MercurySmackTestSuite {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void elementTest() throws URISyntaxException {
|
public void elementTest() throws URISyntaxException, XmlPullParserException, IOException, SmackParsingException {
|
||||||
IkeyType type = IkeyType.OX;
|
IkeyType type = IkeyType.OX;
|
||||||
Date date = new Date();
|
Date date = new Date();
|
||||||
SuperordinateElement superordinate = new SuperordinateElement("" +
|
SuperordinateElement superordinate = new SuperordinateElement("" +
|
||||||
|
@ -33,8 +40,11 @@ public class IkeyElementTest {
|
||||||
ProofElement proof = new ProofElement("d2hpbGUgdGhpcyBpcyBub3QgYSB2YWxpZCBwcm9vZiwgaXQgaXMgc3VmZmljaWVudCBmb3IgdGVzdGluZy4=");
|
ProofElement proof = new ProofElement("d2hpbGUgdGhpcyBpcyBub3QgYSB2YWxpZCBwcm9vZiwgaXQgaXMgc3VmZmljaWVudCBmb3IgdGVzdGluZy4=");
|
||||||
|
|
||||||
IkeyElement ikeyElement = new IkeyElement(type, superordinate, subordinates, proof);
|
IkeyElement ikeyElement = new IkeyElement(type, superordinate, subordinates, proof);
|
||||||
|
String xml = ikeyElement.toXML().toString();
|
||||||
|
|
||||||
System.out.println(ikeyElement.toXML().toString());
|
IkeyElement parsed = IkeyElementProvider.INSTANCE.parse(TestUtils.getParser(xml));
|
||||||
|
|
||||||
|
assertEquals(ikeyElement, parsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SubordinateListElement buildSubListElement(EntityBareJid jid, Date date, SubordinateElement... subordinateElements) {
|
private SubordinateListElement buildSubListElement(EntityBareJid jid, Date date, SubordinateElement... subordinateElements) {
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit d86d20e82a5a490b1ffd31384cb79d0a974b04d5
|
Subproject commit 1c822dcaa4d4cb92d8b2d048f49bb69885143d56
|
Loading…
Reference in a new issue