Reformat code to use tabs
This really sucks to do it like this. Sorry. :(
This commit is contained in:
parent
e8e126f2ce
commit
0423852cb8
File diff suppressed because it is too large
Load Diff
|
@ -21,164 +21,164 @@ import eu.siacs.conversations.entities.Contact;
|
||||||
import eu.siacs.conversations.xml.Element;
|
import eu.siacs.conversations.xml.Element;
|
||||||
|
|
||||||
public class XmppAxolotlMessage {
|
public class XmppAxolotlMessage {
|
||||||
private byte[] innerKey;
|
private byte[] innerKey;
|
||||||
private byte[] ciphertext;
|
private byte[] ciphertext;
|
||||||
private byte[] iv;
|
private byte[] iv;
|
||||||
private final Set<XmppAxolotlMessageHeader> headers;
|
private final Set<XmppAxolotlMessageHeader> headers;
|
||||||
private final Contact contact;
|
private final Contact contact;
|
||||||
private final int sourceDeviceId;
|
private final int sourceDeviceId;
|
||||||
|
|
||||||
public static class XmppAxolotlMessageHeader {
|
public static class XmppAxolotlMessageHeader {
|
||||||
private final int recipientDeviceId;
|
private final int recipientDeviceId;
|
||||||
private final byte[] content;
|
private final byte[] content;
|
||||||
|
|
||||||
public XmppAxolotlMessageHeader(int deviceId, byte[] content) {
|
public XmppAxolotlMessageHeader(int deviceId, byte[] content) {
|
||||||
this.recipientDeviceId = deviceId;
|
this.recipientDeviceId = deviceId;
|
||||||
this.content = content;
|
this.content = content;
|
||||||
}
|
}
|
||||||
|
|
||||||
public XmppAxolotlMessageHeader(Element header) {
|
public XmppAxolotlMessageHeader(Element header) {
|
||||||
if("header".equals(header.getName())) {
|
if("header".equals(header.getName())) {
|
||||||
this.recipientDeviceId = Integer.parseInt(header.getAttribute("rid"));
|
this.recipientDeviceId = Integer.parseInt(header.getAttribute("rid"));
|
||||||
this.content = Base64.decode(header.getContent(),Base64.DEFAULT);
|
this.content = Base64.decode(header.getContent(),Base64.DEFAULT);
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Argument not a <header> Element!");
|
throw new IllegalArgumentException("Argument not a <header> Element!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getRecipientDeviceId() {
|
public int getRecipientDeviceId() {
|
||||||
return recipientDeviceId;
|
return recipientDeviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getContents() {
|
public byte[] getContents() {
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Element toXml() {
|
public Element toXml() {
|
||||||
Element headerElement = new Element("header");
|
Element headerElement = new Element("header");
|
||||||
// TODO: generate XML
|
// TODO: generate XML
|
||||||
headerElement.setAttribute("rid", getRecipientDeviceId());
|
headerElement.setAttribute("rid", getRecipientDeviceId());
|
||||||
headerElement.setContent(Base64.encodeToString(getContents(), Base64.DEFAULT));
|
headerElement.setContent(Base64.encodeToString(getContents(), Base64.DEFAULT));
|
||||||
return headerElement;
|
return headerElement;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class XmppAxolotlPlaintextMessage {
|
public static class XmppAxolotlPlaintextMessage {
|
||||||
private final AxolotlService.XmppAxolotlSession session;
|
private final AxolotlService.XmppAxolotlSession session;
|
||||||
private final String plaintext;
|
private final String plaintext;
|
||||||
|
|
||||||
public XmppAxolotlPlaintextMessage(AxolotlService.XmppAxolotlSession session, String plaintext) {
|
public XmppAxolotlPlaintextMessage(AxolotlService.XmppAxolotlSession session, String plaintext) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
this.plaintext = plaintext;
|
this.plaintext = plaintext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPlaintext() {
|
public String getPlaintext() {
|
||||||
return plaintext;
|
return plaintext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public XmppAxolotlMessage(Contact contact, Element axolotlMessage) {
|
public XmppAxolotlMessage(Contact contact, Element axolotlMessage) {
|
||||||
this.contact = contact;
|
this.contact = contact;
|
||||||
this.sourceDeviceId = Integer.parseInt(axolotlMessage.getAttribute("id"));
|
this.sourceDeviceId = Integer.parseInt(axolotlMessage.getAttribute("id"));
|
||||||
this.headers = new HashSet<>();
|
this.headers = new HashSet<>();
|
||||||
for(Element child:axolotlMessage.getChildren()) {
|
for(Element child:axolotlMessage.getChildren()) {
|
||||||
switch(child.getName()) {
|
switch(child.getName()) {
|
||||||
case "header":
|
case "header":
|
||||||
headers.add(new XmppAxolotlMessageHeader(child));
|
headers.add(new XmppAxolotlMessageHeader(child));
|
||||||
break;
|
break;
|
||||||
case "message":
|
case "message":
|
||||||
iv = Base64.decode(child.getAttribute("iv"),Base64.DEFAULT);
|
iv = Base64.decode(child.getAttribute("iv"),Base64.DEFAULT);
|
||||||
ciphertext = Base64.decode(child.getContent(),Base64.DEFAULT);
|
ciphertext = Base64.decode(child.getContent(),Base64.DEFAULT);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public XmppAxolotlMessage(Contact contact, int sourceDeviceId, String plaintext) {
|
public XmppAxolotlMessage(Contact contact, int sourceDeviceId, String plaintext) {
|
||||||
this.contact = contact;
|
this.contact = contact;
|
||||||
this.sourceDeviceId = sourceDeviceId;
|
this.sourceDeviceId = sourceDeviceId;
|
||||||
this.headers = new HashSet<>();
|
this.headers = new HashSet<>();
|
||||||
this.encrypt(plaintext);
|
this.encrypt(plaintext);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void encrypt(String plaintext) {
|
private void encrypt(String plaintext) {
|
||||||
try {
|
try {
|
||||||
KeyGenerator generator = KeyGenerator.getInstance("AES");
|
KeyGenerator generator = KeyGenerator.getInstance("AES");
|
||||||
generator.init(128);
|
generator.init(128);
|
||||||
SecretKey secretKey = generator.generateKey();
|
SecretKey secretKey = generator.generateKey();
|
||||||
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
|
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
|
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
|
||||||
this.innerKey = secretKey.getEncoded();
|
this.innerKey = secretKey.getEncoded();
|
||||||
this.iv = cipher.getIV();
|
this.iv = cipher.getIV();
|
||||||
this.ciphertext = cipher.doFinal(plaintext.getBytes());
|
this.ciphertext = cipher.doFinal(plaintext.getBytes());
|
||||||
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
|
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
|
||||||
| IllegalBlockSizeException | BadPaddingException e) {
|
| IllegalBlockSizeException | BadPaddingException e) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Contact getContact() {
|
public Contact getContact() {
|
||||||
return this.contact;
|
return this.contact;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSenderDeviceId() {
|
public int getSenderDeviceId() {
|
||||||
return sourceDeviceId;
|
return sourceDeviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getCiphertext() {
|
public byte[] getCiphertext() {
|
||||||
return ciphertext;
|
return ciphertext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<XmppAxolotlMessageHeader> getHeaders() {
|
public Set<XmppAxolotlMessageHeader> getHeaders() {
|
||||||
return headers;
|
return headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addHeader(XmppAxolotlMessageHeader header) {
|
public void addHeader(XmppAxolotlMessageHeader header) {
|
||||||
headers.add(header);
|
headers.add(header);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getInnerKey(){
|
public byte[] getInnerKey(){
|
||||||
return innerKey;
|
return innerKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getIV() {
|
public byte[] getIV() {
|
||||||
return this.iv;
|
return this.iv;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Element toXml() {
|
public Element toXml() {
|
||||||
// TODO: generate outer XML, add in header XML
|
// TODO: generate outer XML, add in header XML
|
||||||
Element message= new Element("axolotl_message", AxolotlService.PEP_PREFIX);
|
Element message= new Element("axolotl_message", AxolotlService.PEP_PREFIX);
|
||||||
message.setAttribute("id", sourceDeviceId);
|
message.setAttribute("id", sourceDeviceId);
|
||||||
for(XmppAxolotlMessageHeader header: headers) {
|
for(XmppAxolotlMessageHeader header: headers) {
|
||||||
message.addChild(header.toXml());
|
message.addChild(header.toXml());
|
||||||
}
|
}
|
||||||
Element payload = message.addChild("message");
|
Element payload = message.addChild("message");
|
||||||
payload.setAttribute("iv",Base64.encodeToString(iv, Base64.DEFAULT));
|
payload.setAttribute("iv",Base64.encodeToString(iv, Base64.DEFAULT));
|
||||||
payload.setContent(Base64.encodeToString(ciphertext,Base64.DEFAULT));
|
payload.setContent(Base64.encodeToString(ciphertext,Base64.DEFAULT));
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public XmppAxolotlPlaintextMessage decrypt(AxolotlService.XmppAxolotlSession session, byte[] key) {
|
public XmppAxolotlPlaintextMessage decrypt(AxolotlService.XmppAxolotlSession session, byte[] key) {
|
||||||
XmppAxolotlPlaintextMessage plaintextMessage = null;
|
XmppAxolotlPlaintextMessage plaintextMessage = null;
|
||||||
try {
|
try {
|
||||||
|
|
||||||
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
|
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
|
||||||
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
|
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
|
||||||
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
||||||
|
|
||||||
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
|
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
|
||||||
|
|
||||||
String plaintext = new String(cipher.doFinal(ciphertext));
|
String plaintext = new String(cipher.doFinal(ciphertext));
|
||||||
plaintextMessage = new XmppAxolotlPlaintextMessage(session, plaintext);
|
plaintextMessage = new XmppAxolotlPlaintextMessage(session, plaintext);
|
||||||
|
|
||||||
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
|
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
|
||||||
| InvalidAlgorithmParameterException | IllegalBlockSizeException
|
| InvalidAlgorithmParameterException | IllegalBlockSizeException
|
||||||
| BadPaddingException e) {
|
| BadPaddingException e) {
|
||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
}
|
}
|
||||||
return plaintextMessage;
|
return plaintextMessage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -310,7 +310,7 @@ public class Contact implements ListItem, Blockable {
|
||||||
synchronized (this.keys) {
|
synchronized (this.keys) {
|
||||||
if (getOtrFingerprints().contains(print)) {
|
if (getOtrFingerprints().contains(print)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
JSONArray fingerprints;
|
JSONArray fingerprints;
|
||||||
if (!this.keys.has("otr_fingerprints")) {
|
if (!this.keys.has("otr_fingerprints")) {
|
||||||
|
@ -392,12 +392,12 @@ public class Contact implements ListItem, Blockable {
|
||||||
public boolean addAxolotlIdentityKey(IdentityKey identityKey) {
|
public boolean addAxolotlIdentityKey(IdentityKey identityKey) {
|
||||||
synchronized (this.keys) {
|
synchronized (this.keys) {
|
||||||
if(!getAxolotlIdentityKeys().contains(identityKey)) {
|
if(!getAxolotlIdentityKeys().contains(identityKey)) {
|
||||||
JSONArray keysList;
|
JSONArray keysList;
|
||||||
try {
|
try {
|
||||||
keysList = this.keys.getJSONArray("axolotl_identity_key");
|
keysList = this.keys.getJSONArray("axolotl_identity_key");
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
keysList = new JSONArray();
|
keysList = new JSONArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
keysList.put(Base64.encodeToString(identityKey.serialize(), Base64.DEFAULT));
|
keysList.put(Base64.encodeToString(identityKey.serialize(), Base64.DEFAULT));
|
||||||
try {
|
try {
|
||||||
|
@ -406,10 +406,10 @@ public class Contact implements ListItem, Blockable {
|
||||||
Log.e(Config.LOGTAG, "Error adding Identity Key to Contact " + this.getJid() + ": " + e.getMessage());
|
Log.e(Config.LOGTAG, "Error adding Identity Key to Contact " + this.getJid() + ": " + e.getMessage());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -147,16 +147,16 @@ public class IqGenerator extends AbstractGenerator {
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IqPacket publishDeviceIds(final List<Integer> ids) {
|
public IqPacket publishDeviceIds(final List<Integer> ids) {
|
||||||
final Element item = new Element("item");
|
final Element item = new Element("item");
|
||||||
final Element list = item.addChild("list", AxolotlService.PEP_PREFIX);
|
final Element list = item.addChild("list", AxolotlService.PEP_PREFIX);
|
||||||
for(Integer id:ids) {
|
for(Integer id:ids) {
|
||||||
final Element device = new Element("device");
|
final Element device = new Element("device");
|
||||||
device.setAttribute("id", id);
|
device.setAttribute("id", id);
|
||||||
list.addChild(device);
|
list.addChild(device);
|
||||||
}
|
}
|
||||||
return publish(AxolotlService.PEP_DEVICE_LIST, item);
|
return publish(AxolotlService.PEP_DEVICE_LIST, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IqPacket publishBundle(final SignedPreKeyRecord signedPreKeyRecord, IdentityKey identityKey, final int deviceId) {
|
public IqPacket publishBundle(final SignedPreKeyRecord signedPreKeyRecord, IdentityKey identityKey, final int deviceId) {
|
||||||
final Element item = new Element("item");
|
final Element item = new Element("item");
|
||||||
|
@ -173,17 +173,17 @@ public class IqGenerator extends AbstractGenerator {
|
||||||
return publish(AxolotlService.PEP_BUNDLE+":"+deviceId, item);
|
return publish(AxolotlService.PEP_BUNDLE+":"+deviceId, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IqPacket publishPreKeys(final List<PreKeyRecord> prekeyList, final int deviceId) {
|
public IqPacket publishPreKeys(final List<PreKeyRecord> prekeyList, final int deviceId) {
|
||||||
final Element item = new Element("item");
|
final Element item = new Element("item");
|
||||||
final Element prekeys = item.addChild("prekeys", AxolotlService.PEP_PREFIX);
|
final Element prekeys = item.addChild("prekeys", AxolotlService.PEP_PREFIX);
|
||||||
for(PreKeyRecord preKeyRecord:prekeyList) {
|
for(PreKeyRecord preKeyRecord:prekeyList) {
|
||||||
final Element prekey = prekeys.addChild("preKeyPublic");
|
final Element prekey = prekeys.addChild("preKeyPublic");
|
||||||
prekey.setAttribute("preKeyId", preKeyRecord.getId());
|
prekey.setAttribute("preKeyId", preKeyRecord.getId());
|
||||||
prekey.setContent(Base64.encodeToString(preKeyRecord.getKeyPair().getPublicKey().serialize(), Base64.DEFAULT));
|
prekey.setContent(Base64.encodeToString(preKeyRecord.getKeyPair().getPublicKey().serialize(), Base64.DEFAULT));
|
||||||
}
|
}
|
||||||
|
|
||||||
return publish(AxolotlService.PEP_PREKEYS+":"+deviceId, item);
|
return publish(AxolotlService.PEP_PREKEYS+":"+deviceId, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IqPacket queryMessageArchiveManagement(final MessageArchiveService.Query mam) {
|
public IqPacket queryMessageArchiveManagement(final MessageArchiveService.Query mam) {
|
||||||
final IqPacket packet = new IqPacket(IqPacket.TYPE.SET);
|
final IqPacket packet = new IqPacket(IqPacket.TYPE.SET);
|
||||||
|
|
|
@ -66,19 +66,19 @@ public class MessageGenerator extends AbstractGenerator {
|
||||||
delay.setAttribute("stamp", mDateFormat.format(date));
|
delay.setAttribute("stamp", mDateFormat.format(date));
|
||||||
}
|
}
|
||||||
|
|
||||||
public MessagePacket generateAxolotlChat(Message message) throws NoSessionsCreatedException{
|
public MessagePacket generateAxolotlChat(Message message) throws NoSessionsCreatedException{
|
||||||
return generateAxolotlChat(message, false);
|
return generateAxolotlChat(message, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MessagePacket generateAxolotlChat(Message message, boolean addDelay) throws NoSessionsCreatedException{
|
public MessagePacket generateAxolotlChat(Message message, boolean addDelay) throws NoSessionsCreatedException{
|
||||||
MessagePacket packet = preparePacket(message, addDelay);
|
MessagePacket packet = preparePacket(message, addDelay);
|
||||||
AxolotlService service = message.getConversation().getAccount().getAxolotlService();
|
AxolotlService service = message.getConversation().getAccount().getAxolotlService();
|
||||||
Log.d(Config.LOGTAG, "Submitting message to axolotl service for send processing...");
|
Log.d(Config.LOGTAG, "Submitting message to axolotl service for send processing...");
|
||||||
XmppAxolotlMessage axolotlMessage = service.processSending(message.getContact(),
|
XmppAxolotlMessage axolotlMessage = service.processSending(message.getContact(),
|
||||||
message.getBody());
|
message.getBody());
|
||||||
packet.setAxolotlMessage(axolotlMessage.toXml());
|
packet.setAxolotlMessage(axolotlMessage.toXml());
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MessagePacket generateOtrChat(Message message) {
|
public MessagePacket generateOtrChat(Message message) {
|
||||||
return generateOtrChat(message, false);
|
return generateOtrChat(message, false);
|
||||||
|
|
|
@ -70,7 +70,7 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
|
||||||
|
|
||||||
public String avatarData(final IqPacket packet) {
|
public String avatarData(final IqPacket packet) {
|
||||||
final Element pubsub = packet.findChild("pubsub",
|
final Element pubsub = packet.findChild("pubsub",
|
||||||
"http://jabber.org/protocol/pubsub");
|
"http://jabber.org/protocol/pubsub");
|
||||||
if (pubsub == null) {
|
if (pubsub == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -165,19 +165,19 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
|
||||||
|
|
||||||
public Map<Integer, ECPublicKey> preKeyPublics(final IqPacket packet) {
|
public Map<Integer, ECPublicKey> preKeyPublics(final IqPacket packet) {
|
||||||
Map<Integer, ECPublicKey> preKeyRecords = new HashMap<>();
|
Map<Integer, ECPublicKey> preKeyRecords = new HashMap<>();
|
||||||
Element prekeysItem = getItem(packet);
|
Element prekeysItem = getItem(packet);
|
||||||
if (prekeysItem == null) {
|
if (prekeysItem == null) {
|
||||||
Log.d(Config.LOGTAG, "Couldn't find <item> in preKeyPublic IQ packet: " + packet);
|
Log.d(Config.LOGTAG, "Couldn't find <item> in preKeyPublic IQ packet: " + packet);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final Element prekeysElement = prekeysItem.findChild("prekeys");
|
final Element prekeysElement = prekeysItem.findChild("prekeys");
|
||||||
if(prekeysElement == null) {
|
if(prekeysElement == null) {
|
||||||
Log.d(Config.LOGTAG, "Couldn't find <prekeys> in preKeyPublic IQ packet: " + packet);
|
Log.d(Config.LOGTAG, "Couldn't find <prekeys> in preKeyPublic IQ packet: " + packet);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
for(Element preKeyPublicElement : prekeysElement.getChildren()) {
|
for(Element preKeyPublicElement : prekeysElement.getChildren()) {
|
||||||
if(!preKeyPublicElement.getName().equals("preKeyPublic")){
|
if(!preKeyPublicElement.getName().equals("preKeyPublic")){
|
||||||
Log.d(Config.LOGTAG, "Encountered unexpected tag in prekeys list: " + preKeyPublicElement);
|
Log.d(Config.LOGTAG, "Encountered unexpected tag in prekeys list: " + preKeyPublicElement);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Integer preKeyId = Integer.valueOf(preKeyPublicElement.getAttribute("preKeyId"));
|
Integer preKeyId = Integer.valueOf(preKeyPublicElement.getAttribute("preKeyId"));
|
||||||
|
@ -192,37 +192,37 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
|
||||||
return preKeyRecords;
|
return preKeyRecords;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PreKeyBundle bundle(final IqPacket bundle) {
|
public PreKeyBundle bundle(final IqPacket bundle) {
|
||||||
Element bundleItem = getItem(bundle);
|
Element bundleItem = getItem(bundle);
|
||||||
if(bundleItem == null) {
|
if(bundleItem == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final Element bundleElement = bundleItem.findChild("bundle");
|
final Element bundleElement = bundleItem.findChild("bundle");
|
||||||
if(bundleElement == null) {
|
if(bundleElement == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
ECPublicKey signedPreKeyPublic = signedPreKeyPublic(bundleElement);
|
ECPublicKey signedPreKeyPublic = signedPreKeyPublic(bundleElement);
|
||||||
Integer signedPreKeyId = signedPreKeyId(bundleElement);
|
Integer signedPreKeyId = signedPreKeyId(bundleElement);
|
||||||
byte[] signedPreKeySignature = signedPreKeySignature(bundleElement);
|
byte[] signedPreKeySignature = signedPreKeySignature(bundleElement);
|
||||||
IdentityKey identityKey = identityKey(bundleElement);
|
IdentityKey identityKey = identityKey(bundleElement);
|
||||||
if(signedPreKeyPublic == null || identityKey == null) {
|
if(signedPreKeyPublic == null || identityKey == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new PreKeyBundle(0, 0, 0, null,
|
return new PreKeyBundle(0, 0, 0, null,
|
||||||
signedPreKeyId, signedPreKeyPublic, signedPreKeySignature, identityKey);
|
signedPreKeyId, signedPreKeyPublic, signedPreKeySignature, identityKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<PreKeyBundle> preKeys(final IqPacket preKeys) {
|
public List<PreKeyBundle> preKeys(final IqPacket preKeys) {
|
||||||
List<PreKeyBundle> bundles = new ArrayList<>();
|
List<PreKeyBundle> bundles = new ArrayList<>();
|
||||||
Map<Integer, ECPublicKey> preKeyPublics = preKeyPublics(preKeys);
|
Map<Integer, ECPublicKey> preKeyPublics = preKeyPublics(preKeys);
|
||||||
if ( preKeyPublics != null) {
|
if ( preKeyPublics != null) {
|
||||||
for (Integer preKeyId : preKeyPublics.keySet()) {
|
for (Integer preKeyId : preKeyPublics.keySet()) {
|
||||||
ECPublicKey preKeyPublic = preKeyPublics.get(preKeyId);
|
ECPublicKey preKeyPublic = preKeyPublics.get(preKeyId);
|
||||||
bundles.add(new PreKeyBundle(0, 0, preKeyId, preKeyPublic,
|
bundles.add(new PreKeyBundle(0, 0, preKeyId, preKeyPublic,
|
||||||
0, null, null, null));
|
0, null, null, null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return bundles;
|
return bundles;
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,17 +98,17 @@ public class MessageParser extends AbstractParser implements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Message parseAxolotlChat(Element axolotlMessage, Jid from, String id, Conversation conversation) {
|
private Message parseAxolotlChat(Element axolotlMessage, Jid from, String id, Conversation conversation) {
|
||||||
Message finishedMessage = null;
|
Message finishedMessage = null;
|
||||||
AxolotlService service = conversation.getAccount().getAxolotlService();
|
AxolotlService service = conversation.getAccount().getAxolotlService();
|
||||||
XmppAxolotlMessage xmppAxolotlMessage = new XmppAxolotlMessage(conversation.getContact(), axolotlMessage);
|
XmppAxolotlMessage xmppAxolotlMessage = new XmppAxolotlMessage(conversation.getContact(), axolotlMessage);
|
||||||
XmppAxolotlMessage.XmppAxolotlPlaintextMessage plaintextMessage = service.processReceiving(xmppAxolotlMessage);
|
XmppAxolotlMessage.XmppAxolotlPlaintextMessage plaintextMessage = service.processReceiving(xmppAxolotlMessage);
|
||||||
if(plaintextMessage != null) {
|
if(plaintextMessage != null) {
|
||||||
finishedMessage = new Message(conversation, plaintextMessage.getPlaintext(), Message.ENCRYPTION_AXOLOTL, Message.STATUS_RECEIVED);
|
finishedMessage = new Message(conversation, plaintextMessage.getPlaintext(), Message.ENCRYPTION_AXOLOTL, Message.STATUS_RECEIVED);
|
||||||
}
|
}
|
||||||
|
|
||||||
return finishedMessage;
|
return finishedMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Invite {
|
private class Invite {
|
||||||
Jid jid;
|
Jid jid;
|
||||||
|
@ -187,17 +187,17 @@ public class MessageParser extends AbstractParser implements
|
||||||
mXmppConnectionService.updateAccountUi();
|
mXmppConnectionService.updateAccountUi();
|
||||||
}
|
}
|
||||||
} else if (AxolotlService.PEP_DEVICE_LIST.equals(node)) {
|
} else if (AxolotlService.PEP_DEVICE_LIST.equals(node)) {
|
||||||
Log.d(Config.LOGTAG, "Received PEP device list update from "+ from + ", processing...");
|
Log.d(Config.LOGTAG, "Received PEP device list update from "+ from + ", processing...");
|
||||||
Element item = items.findChild("item");
|
Element item = items.findChild("item");
|
||||||
List<Integer> deviceIds = mXmppConnectionService.getIqParser().deviceIds(item);
|
List<Integer> deviceIds = mXmppConnectionService.getIqParser().deviceIds(item);
|
||||||
AxolotlService axolotlService = account.getAxolotlService();
|
AxolotlService axolotlService = account.getAxolotlService();
|
||||||
if(account.getJid().toBareJid().equals(from)) {
|
if(account.getJid().toBareJid().equals(from)) {
|
||||||
} else {
|
} else {
|
||||||
Contact contact = account.getRoster().getContact(from);
|
Contact contact = account.getRoster().getContact(from);
|
||||||
for (Integer deviceId : deviceIds) {
|
for (Integer deviceId : deviceIds) {
|
||||||
axolotlService.fetchBundleIfNeeded(contact, deviceId);
|
axolotlService.fetchBundleIfNeeded(contact, deviceId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,7 +262,7 @@ public class MessageParser extends AbstractParser implements
|
||||||
final String body = packet.getBody();
|
final String body = packet.getBody();
|
||||||
final Element mucUserElement = packet.findChild("x","http://jabber.org/protocol/muc#user");
|
final Element mucUserElement = packet.findChild("x","http://jabber.org/protocol/muc#user");
|
||||||
final String pgpEncrypted = packet.findChildContent("x", "jabber:x:encrypted");
|
final String pgpEncrypted = packet.findChildContent("x", "jabber:x:encrypted");
|
||||||
final Element axolotlEncrypted = packet.findChild("axolotl_message", AxolotlService.PEP_PREFIX);
|
final Element axolotlEncrypted = packet.findChild("axolotl_message", AxolotlService.PEP_PREFIX);
|
||||||
int status;
|
int status;
|
||||||
final Jid counterpart;
|
final Jid counterpart;
|
||||||
final Jid to = packet.getTo();
|
final Jid to = packet.getTo();
|
||||||
|
@ -324,13 +324,13 @@ public class MessageParser extends AbstractParser implements
|
||||||
message = new Message(conversation, body, Message.ENCRYPTION_NONE, status);
|
message = new Message(conversation, body, Message.ENCRYPTION_NONE, status);
|
||||||
}
|
}
|
||||||
} else if (pgpEncrypted != null) {
|
} else if (pgpEncrypted != null) {
|
||||||
message = new Message(conversation, pgpEncrypted, Message.ENCRYPTION_PGP, status);
|
message = new Message(conversation, pgpEncrypted, Message.ENCRYPTION_PGP, status);
|
||||||
} else if (axolotlEncrypted != null) {
|
} else if (axolotlEncrypted != null) {
|
||||||
message = parseAxolotlChat(axolotlEncrypted, from, remoteMsgId, conversation);
|
message = parseAxolotlChat(axolotlEncrypted, from, remoteMsgId, conversation);
|
||||||
if (message == null) {
|
if (message == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
message = new Message(conversation, body, Message.ENCRYPTION_NONE, status);
|
message = new Message(conversation, body, Message.ENCRYPTION_NONE, status);
|
||||||
}
|
}
|
||||||
message.setCounterpart(counterpart);
|
message.setCounterpart(counterpart);
|
||||||
|
|
|
@ -42,7 +42,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
|
||||||
+ Contact.JID + " TEXT," + Contact.KEYS + " TEXT,"
|
+ Contact.JID + " TEXT," + Contact.KEYS + " TEXT,"
|
||||||
+ Contact.PHOTOURI + " TEXT," + Contact.OPTIONS + " NUMBER,"
|
+ Contact.PHOTOURI + " TEXT," + Contact.OPTIONS + " NUMBER,"
|
||||||
+ Contact.SYSTEMACCOUNT + " NUMBER, " + Contact.AVATAR + " TEXT, "
|
+ Contact.SYSTEMACCOUNT + " NUMBER, " + Contact.AVATAR + " TEXT, "
|
||||||
+ Contact.LAST_PRESENCE + " TEXT, " + Contact.LAST_TIME + " NUMBER, "
|
+ Contact.LAST_PRESENCE + " TEXT, " + Contact.LAST_TIME + " NUMBER, "
|
||||||
+ Contact.GROUPS + " TEXT, FOREIGN KEY(" + Contact.ACCOUNT + ") REFERENCES "
|
+ Contact.GROUPS + " TEXT, FOREIGN KEY(" + Contact.ACCOUNT + ") REFERENCES "
|
||||||
+ Account.TABLENAME + "(" + Account.UUID
|
+ Account.TABLENAME + "(" + Account.UUID
|
||||||
+ ") ON DELETE CASCADE, UNIQUE(" + Contact.ACCOUNT + ", "
|
+ ") ON DELETE CASCADE, UNIQUE(" + Contact.ACCOUNT + ", "
|
||||||
|
@ -75,14 +75,14 @@ public class DatabaseBackend extends SQLiteOpenHelper {
|
||||||
private static String CREATE_SESSIONS_STATEMENT = "CREATE TABLE "
|
private static String CREATE_SESSIONS_STATEMENT = "CREATE TABLE "
|
||||||
+ AxolotlService.SQLiteAxolotlStore.SESSION_TABLENAME + "("
|
+ AxolotlService.SQLiteAxolotlStore.SESSION_TABLENAME + "("
|
||||||
+ AxolotlService.SQLiteAxolotlStore.ACCOUNT + " TEXT, "
|
+ AxolotlService.SQLiteAxolotlStore.ACCOUNT + " TEXT, "
|
||||||
+ AxolotlService.SQLiteAxolotlStore.NAME + " TEXT, "
|
+ AxolotlService.SQLiteAxolotlStore.NAME + " TEXT, "
|
||||||
+ AxolotlService.SQLiteAxolotlStore.DEVICE_ID + " INTEGER, "
|
+ AxolotlService.SQLiteAxolotlStore.DEVICE_ID + " INTEGER, "
|
||||||
+ AxolotlService.SQLiteAxolotlStore.TRUSTED + " INTEGER, "
|
+ AxolotlService.SQLiteAxolotlStore.TRUSTED + " INTEGER, "
|
||||||
+ AxolotlService.SQLiteAxolotlStore.KEY + " TEXT, FOREIGN KEY("
|
+ AxolotlService.SQLiteAxolotlStore.KEY + " TEXT, FOREIGN KEY("
|
||||||
+ AxolotlService.SQLiteAxolotlStore.ACCOUNT
|
+ AxolotlService.SQLiteAxolotlStore.ACCOUNT
|
||||||
+ ") REFERENCES " + Account.TABLENAME + "(" + Account.UUID + ") ON DELETE CASCADE, "
|
+ ") REFERENCES " + Account.TABLENAME + "(" + Account.UUID + ") ON DELETE CASCADE, "
|
||||||
+ "UNIQUE( " + AxolotlService.SQLiteAxolotlStore.ACCOUNT + ", "
|
+ "UNIQUE( " + AxolotlService.SQLiteAxolotlStore.ACCOUNT + ", "
|
||||||
+ AxolotlService.SQLiteAxolotlStore.NAME + ", "
|
+ AxolotlService.SQLiteAxolotlStore.NAME + ", "
|
||||||
+ AxolotlService.SQLiteAxolotlStore.DEVICE_ID
|
+ AxolotlService.SQLiteAxolotlStore.DEVICE_ID
|
||||||
+ ") ON CONFLICT REPLACE"
|
+ ") ON CONFLICT REPLACE"
|
||||||
+");";
|
+");";
|
||||||
|
@ -157,12 +157,12 @@ public class DatabaseBackend extends SQLiteOpenHelper {
|
||||||
db.execSQL("ALTER TABLE " + Conversation.TABLENAME + " ADD COLUMN "
|
db.execSQL("ALTER TABLE " + Conversation.TABLENAME + " ADD COLUMN "
|
||||||
+ Conversation.ATTRIBUTES + " TEXT");
|
+ Conversation.ATTRIBUTES + " TEXT");
|
||||||
}
|
}
|
||||||
if (oldVersion < 9 && newVersion >= 9) {
|
if (oldVersion < 9 && newVersion >= 9) {
|
||||||
db.execSQL("ALTER TABLE " + Contact.TABLENAME + " ADD COLUMN "
|
db.execSQL("ALTER TABLE " + Contact.TABLENAME + " ADD COLUMN "
|
||||||
+ Contact.LAST_TIME + " NUMBER");
|
+ Contact.LAST_TIME + " NUMBER");
|
||||||
db.execSQL("ALTER TABLE " + Contact.TABLENAME + " ADD COLUMN "
|
db.execSQL("ALTER TABLE " + Contact.TABLENAME + " ADD COLUMN "
|
||||||
+ Contact.LAST_PRESENCE + " TEXT");
|
+ Contact.LAST_PRESENCE + " TEXT");
|
||||||
}
|
}
|
||||||
if (oldVersion < 10 && newVersion >= 10) {
|
if (oldVersion < 10 && newVersion >= 10) {
|
||||||
db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN "
|
db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN "
|
||||||
+ Message.RELATIVE_FILE_PATH + " TEXT");
|
+ Message.RELATIVE_FILE_PATH + " TEXT");
|
||||||
|
@ -557,7 +557,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
|
||||||
|
|
||||||
public SessionRecord loadSession(Account account, AxolotlAddress contact) {
|
public SessionRecord loadSession(Account account, AxolotlAddress contact) {
|
||||||
SessionRecord session = null;
|
SessionRecord session = null;
|
||||||
Cursor cursor = getCursorForSession(account, contact);
|
Cursor cursor = getCursorForSession(account, contact);
|
||||||
if(cursor.getCount() != 0) {
|
if(cursor.getCount() != 0) {
|
||||||
cursor.moveToFirst();
|
cursor.moveToFirst();
|
||||||
try {
|
try {
|
||||||
|
@ -565,8 +565,8 @@ public class DatabaseBackend extends SQLiteOpenHelper {
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cursor.close();
|
cursor.close();
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -635,7 +635,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
|
||||||
Cursor cursor = getCursorForSession(account, contact);
|
Cursor cursor = getCursorForSession(account, contact);
|
||||||
if(cursor.getCount() != 0) {
|
if(cursor.getCount() != 0) {
|
||||||
cursor.moveToFirst();
|
cursor.moveToFirst();
|
||||||
trusted = cursor.getInt(cursor.getColumnIndex(
|
trusted = cursor.getInt(cursor.getColumnIndex(
|
||||||
AxolotlService.SQLiteAxolotlStore.TRUSTED)) > 0;
|
AxolotlService.SQLiteAxolotlStore.TRUSTED)) > 0;
|
||||||
}
|
}
|
||||||
cursor.close();
|
cursor.close();
|
||||||
|
|
|
@ -273,9 +273,9 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
syncDirtyContacts(account);
|
syncDirtyContacts(account);
|
||||||
account.getAxolotlService().publishOwnDeviceIdIfNeeded();
|
account.getAxolotlService().publishOwnDeviceIdIfNeeded();
|
||||||
account.getAxolotlService().publishBundleIfNeeded();
|
account.getAxolotlService().publishBundleIfNeeded();
|
||||||
account.getAxolotlService().publishPreKeysIfNeeded();
|
account.getAxolotlService().publishPreKeysIfNeeded();
|
||||||
|
|
||||||
scheduleWakeUpCall(Config.PING_MAX_INTERVAL, account.getUuid().hashCode());
|
scheduleWakeUpCall(Config.PING_MAX_INTERVAL, account.getUuid().hashCode());
|
||||||
} else if (account.getStatus() == Account.State.OFFLINE) {
|
} else if (account.getStatus() == Account.State.OFFLINE) {
|
||||||
|
|
|
@ -755,16 +755,16 @@ public class ConversationActivity extends XmppActivity
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case R.id.encryption_choice_axolotl:
|
case R.id.encryption_choice_axolotl:
|
||||||
Log.d(Config.LOGTAG, "Trying to enable axolotl...");
|
Log.d(Config.LOGTAG, "Trying to enable axolotl...");
|
||||||
if(conversation.getAccount().getAxolotlService().isContactAxolotlCapable(conversation.getContact())) {
|
if(conversation.getAccount().getAxolotlService().isContactAxolotlCapable(conversation.getContact())) {
|
||||||
Log.d(Config.LOGTAG, "Enabled axolotl for Contact " + conversation.getContact().getJid() );
|
Log.d(Config.LOGTAG, "Enabled axolotl for Contact " + conversation.getContact().getJid() );
|
||||||
conversation.setNextEncryption(Message.ENCRYPTION_AXOLOTL);
|
conversation.setNextEncryption(Message.ENCRYPTION_AXOLOTL);
|
||||||
item.setChecked(true);
|
item.setChecked(true);
|
||||||
} else {
|
} else {
|
||||||
Log.d(Config.LOGTAG, "Contact " + conversation.getContact().getJid() + " not axolotl capable!");
|
Log.d(Config.LOGTAG, "Contact " + conversation.getContact().getJid() + " not axolotl capable!");
|
||||||
showAxolotlNoSessionsDialog();
|
showAxolotlNoSessionsDialog();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
conversation.setNextEncryption(Message.ENCRYPTION_NONE);
|
conversation.setNextEncryption(Message.ENCRYPTION_NONE);
|
||||||
break;
|
break;
|
||||||
|
@ -798,7 +798,7 @@ public class ConversationActivity extends XmppActivity
|
||||||
.setChecked(true);
|
.setChecked(true);
|
||||||
break;
|
break;
|
||||||
case Message.ENCRYPTION_AXOLOTL:
|
case Message.ENCRYPTION_AXOLOTL:
|
||||||
Log.d(Config.LOGTAG, "Axolotl confirmed. Setting menu item checked!");
|
Log.d(Config.LOGTAG, "Axolotl confirmed. Setting menu item checked!");
|
||||||
popup.getMenu().findItem(R.id.encryption_choice_axolotl)
|
popup.getMenu().findItem(R.id.encryption_choice_axolotl)
|
||||||
.setChecked(true);
|
.setChecked(true);
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue