refactored omemo to take multiple recipients
This commit is contained in:
parent
199ae3a4d8
commit
9e0466d1e6
|
@ -81,8 +81,8 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean fetchMapHasErrors(Contact contact) {
|
public boolean fetchMapHasErrors(List<Jid> jids) {
|
||||||
Jid jid = contact.getJid().toBareJid();
|
for(Jid jid : jids) {
|
||||||
if (deviceIds.get(jid) != null) {
|
if (deviceIds.get(jid) != null) {
|
||||||
for (Integer foreignId : this.deviceIds.get(jid)) {
|
for (Integer foreignId : this.deviceIds.get(jid)) {
|
||||||
AxolotlAddress address = new AxolotlAddress(jid.toString(), foreignId);
|
AxolotlAddress address = new AxolotlAddress(jid.toString(), foreignId);
|
||||||
|
@ -91,6 +91,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,12 +243,29 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
|
||||||
return axolotlStore.getContactKeysWithTrust(account.getJid().toBareJid().toString(), trust);
|
return axolotlStore.getContactKeysWithTrust(account.getJid().toBareJid().toString(), trust);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<IdentityKey> getKeysWithTrust(XmppAxolotlSession.Trust trust, Contact contact) {
|
public Set<IdentityKey> getKeysWithTrust(XmppAxolotlSession.Trust trust, Jid jid) {
|
||||||
return axolotlStore.getContactKeysWithTrust(contact.getJid().toBareJid().toString(), trust);
|
return axolotlStore.getContactKeysWithTrust(jid.toBareJid().toString(), trust);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getNumTrustedKeys(Contact contact) {
|
public Set<IdentityKey> getKeysWithTrust(XmppAxolotlSession.Trust trust, List<Jid> jids) {
|
||||||
return axolotlStore.getContactNumTrustedKeys(contact.getJid().toBareJid().toString());
|
Set<IdentityKey> keys = new HashSet<>();
|
||||||
|
for(Jid jid : jids) {
|
||||||
|
keys.addAll(axolotlStore.getContactKeysWithTrust(jid.toString(), trust));
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getNumTrustedKeys(Jid jid) {
|
||||||
|
return axolotlStore.getContactNumTrustedKeys(jid.toBareJid().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean anyTargetHasNoTrustedKeys(List<Jid> jids) {
|
||||||
|
for(Jid jid : jids) {
|
||||||
|
if (axolotlStore.getContactNumTrustedKeys(jid.toBareJid().toString()) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AxolotlAddress getAddressForJid(Jid jid) {
|
private AxolotlAddress getAddressForJid(Jid jid) {
|
||||||
|
@ -259,11 +277,19 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
|
||||||
return new HashSet<>(this.sessions.getAll(ownAddress).values());
|
return new HashSet<>(this.sessions.getAll(ownAddress).values());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<XmppAxolotlSession> findSessionsforContact(Contact contact) {
|
private Set<XmppAxolotlSession> findSessionsForContact(Contact contact) {
|
||||||
AxolotlAddress contactAddress = getAddressForJid(contact.getJid());
|
AxolotlAddress contactAddress = getAddressForJid(contact.getJid());
|
||||||
return new HashSet<>(this.sessions.getAll(contactAddress).values());
|
return new HashSet<>(this.sessions.getAll(contactAddress).values());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Set<XmppAxolotlSession> findSessionsForConversation(Conversation conversation) {
|
||||||
|
HashSet<XmppAxolotlSession> sessions = new HashSet<>();
|
||||||
|
for(Jid jid : getCryptoTargets(conversation)) {
|
||||||
|
sessions.addAll(this.sessions.getAll(getAddressForJid(jid)).values());
|
||||||
|
}
|
||||||
|
return sessions;
|
||||||
|
}
|
||||||
|
|
||||||
public Set<String> getFingerprintsForOwnSessions() {
|
public Set<String> getFingerprintsForOwnSessions() {
|
||||||
Set<String> fingerprints = new HashSet<>();
|
Set<String> fingerprints = new HashSet<>();
|
||||||
for (XmppAxolotlSession session : findOwnSessions()) {
|
for (XmppAxolotlSession session : findOwnSessions()) {
|
||||||
|
@ -274,15 +300,14 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
|
||||||
|
|
||||||
public Set<String> getFingerprintsForContact(final Contact contact) {
|
public Set<String> getFingerprintsForContact(final Contact contact) {
|
||||||
Set<String> fingerprints = new HashSet<>();
|
Set<String> fingerprints = new HashSet<>();
|
||||||
for (XmppAxolotlSession session : findSessionsforContact(contact)) {
|
for (XmppAxolotlSession session : findSessionsForContact(contact)) {
|
||||||
fingerprints.add(session.getFingerprint());
|
fingerprints.add(session.getFingerprint());
|
||||||
}
|
}
|
||||||
return fingerprints;
|
return fingerprints;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasAny(Contact contact) {
|
private boolean hasAny(Jid jid) {
|
||||||
AxolotlAddress contactAddress = getAddressForJid(contact.getJid());
|
return sessions.hasAny(getAddressForJid(jid));
|
||||||
return sessions.hasAny(contactAddress);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPepBroken() {
|
public boolean isPepBroken() {
|
||||||
|
@ -594,10 +619,25 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isContactAxolotlCapable(Contact contact) {
|
public boolean isConversationAxolotlCapable(Conversation conversation) {
|
||||||
Jid jid = contact.getJid().toBareJid();
|
final List<Jid> jids = getCryptoTargets(conversation);
|
||||||
return hasAny(contact) ||
|
for(Jid jid : jids) {
|
||||||
(deviceIds.containsKey(jid) && !deviceIds.get(jid).isEmpty());
|
if (!hasAny(jid) && (!deviceIds.containsKey(jid) || deviceIds.get(jid).isEmpty())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return jids.size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Jid> getCryptoTargets(Conversation conversation) {
|
||||||
|
final List<Jid> jids;
|
||||||
|
if (conversation.getMode() == Conversation.MODE_SINGLE) {
|
||||||
|
jids = Arrays.asList(conversation.getJid().toBareJid());
|
||||||
|
} else {
|
||||||
|
jids = conversation.getMucOptions().getMembers();
|
||||||
|
jids.remove(account.getJid().toBareJid());
|
||||||
|
}
|
||||||
|
return jids;
|
||||||
}
|
}
|
||||||
|
|
||||||
public XmppAxolotlSession.Trust getFingerprintTrust(String fingerprint) {
|
public XmppAxolotlSession.Trust getFingerprintTrust(String fingerprint) {
|
||||||
|
@ -753,15 +793,12 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<AxolotlAddress> findDevicesWithoutSession(final Conversation conversation) {
|
public Set<AxolotlAddress> findDevicesWithoutSession(final Conversation conversation) {
|
||||||
return findDevicesWithoutSession(conversation.getContact().getJid().toBareJid());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<AxolotlAddress> findDevicesWithoutSession(final Jid contactJid) {
|
|
||||||
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Finding devices without session for " + contactJid);
|
|
||||||
Set<AxolotlAddress> addresses = new HashSet<>();
|
Set<AxolotlAddress> addresses = new HashSet<>();
|
||||||
if (deviceIds.get(contactJid) != null) {
|
for(Jid jid : getCryptoTargets(conversation)) {
|
||||||
for (Integer foreignId : this.deviceIds.get(contactJid)) {
|
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Finding devices without session for " + jid);
|
||||||
AxolotlAddress address = new AxolotlAddress(contactJid.toString(), foreignId);
|
if (deviceIds.get(jid) != null) {
|
||||||
|
for (Integer foreignId : this.deviceIds.get(jid)) {
|
||||||
|
AxolotlAddress address = new AxolotlAddress(jid.toString(), foreignId);
|
||||||
if (sessions.get(address) == null) {
|
if (sessions.get(address) == null) {
|
||||||
IdentityKey identityKey = axolotlStore.loadSession(address).getSessionState().getRemoteIdentityKey();
|
IdentityKey identityKey = axolotlStore.loadSession(address).getSessionState().getRemoteIdentityKey();
|
||||||
if (identityKey != null) {
|
if (identityKey != null) {
|
||||||
|
@ -769,11 +806,11 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
|
||||||
XmppAxolotlSession session = new XmppAxolotlSession(account, axolotlStore, address, identityKey);
|
XmppAxolotlSession session = new XmppAxolotlSession(account, axolotlStore, address, identityKey);
|
||||||
sessions.put(address, session);
|
sessions.put(address, session);
|
||||||
} else {
|
} else {
|
||||||
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Found device " + contactJid + ":" + foreignId);
|
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Found device " + jid + ":" + foreignId);
|
||||||
if (fetchStatusMap.get(address) != FetchStatus.ERROR) {
|
if (fetchStatusMap.get(address) != FetchStatus.ERROR) {
|
||||||
addresses.add(address);
|
addresses.add(address);
|
||||||
} else {
|
} else {
|
||||||
Log.d(Config.LOGTAG,getLogprefix(account)+"skipping over "+address+" because it's broken");
|
Log.d(Config.LOGTAG, getLogprefix(account) + "skipping over " + address + " because it's broken");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -781,6 +818,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
|
||||||
} else {
|
} else {
|
||||||
Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Have no target devices in PEP!");
|
Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Have no target devices in PEP!");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (deviceIds.get(account.getJid().toBareJid()) != null) {
|
if (deviceIds.get(account.getJid().toBareJid()) != null) {
|
||||||
for (Integer ownId : this.deviceIds.get(account.getJid().toBareJid())) {
|
for (Integer ownId : this.deviceIds.get(account.getJid().toBareJid())) {
|
||||||
AxolotlAddress address = new AxolotlAddress(account.getJid().toBareJid().toString(), ownId);
|
AxolotlAddress address = new AxolotlAddress(account.getJid().toBareJid().toString(), ownId);
|
||||||
|
@ -827,7 +865,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean trustedSessionVerified(final Conversation conversation) {
|
public boolean trustedSessionVerified(final Conversation conversation) {
|
||||||
Set<XmppAxolotlSession> sessions = findSessionsforContact(conversation.getContact());
|
Set<XmppAxolotlSession> sessions = findSessionsForConversation(conversation);
|
||||||
sessions.addAll(findOwnSessions());
|
sessions.addAll(findOwnSessions());
|
||||||
boolean verified = false;
|
boolean verified = false;
|
||||||
for(XmppAxolotlSession session : sessions) {
|
for(XmppAxolotlSession session : sessions) {
|
||||||
|
@ -842,26 +880,32 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
|
||||||
return verified;
|
return verified;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasPendingKeyFetches(Account account, Contact contact) {
|
public boolean hasPendingKeyFetches(Account account, List<Jid> jids) {
|
||||||
AxolotlAddress ownAddress = new AxolotlAddress(account.getJid().toBareJid().toString(), 0);
|
AxolotlAddress ownAddress = new AxolotlAddress(account.getJid().toBareJid().toString(), 0);
|
||||||
AxolotlAddress foreignAddress = new AxolotlAddress(contact.getJid().toBareJid().toString(), 0);
|
if (fetchStatusMap.getAll(ownAddress).containsValue(FetchStatus.PENDING)) {
|
||||||
return fetchStatusMap.getAll(ownAddress).containsValue(FetchStatus.PENDING)
|
return true;
|
||||||
|| fetchStatusMap.getAll(foreignAddress).containsValue(FetchStatus.PENDING);
|
}
|
||||||
|
for(Jid jid : jids) {
|
||||||
|
AxolotlAddress foreignAddress = new AxolotlAddress(jid.toBareJid().toString(), 0);
|
||||||
|
if (fetchStatusMap.getAll(foreignAddress).containsValue(FetchStatus.PENDING)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private XmppAxolotlMessage buildHeader(Contact contact) {
|
private XmppAxolotlMessage buildHeader(Conversation conversation) {
|
||||||
final XmppAxolotlMessage axolotlMessage = new XmppAxolotlMessage(
|
final XmppAxolotlMessage axolotlMessage = new XmppAxolotlMessage(
|
||||||
contact.getJid().toBareJid(), getOwnDeviceId());
|
account.getJid().toBareJid(), getOwnDeviceId());
|
||||||
|
|
||||||
Set<XmppAxolotlSession> contactSessions = findSessionsforContact(contact);
|
Set<XmppAxolotlSession> remoteSessions = findSessionsForConversation(conversation);
|
||||||
Set<XmppAxolotlSession> ownSessions = findOwnSessions();
|
Set<XmppAxolotlSession> ownSessions = findOwnSessions();
|
||||||
if (contactSessions.isEmpty()) {
|
if (remoteSessions.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Building axolotl foreign keyElements...");
|
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Building axolotl foreign keyElements...");
|
||||||
for (XmppAxolotlSession session : contactSessions) {
|
for (XmppAxolotlSession session : remoteSessions) {
|
||||||
Log.v(Config.LOGTAG, AxolotlService.getLogprefix(account) + session.getRemoteAddress().toString());
|
Log.v(Config.LOGTAG, AxolotlService.getLogprefix(account) + session.getRemoteAddress().toString());
|
||||||
axolotlMessage.addDevice(session);
|
axolotlMessage.addDevice(session);
|
||||||
}
|
}
|
||||||
|
@ -876,7 +920,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public XmppAxolotlMessage encrypt(Message message) {
|
public XmppAxolotlMessage encrypt(Message message) {
|
||||||
XmppAxolotlMessage axolotlMessage = buildHeader(message.getContact());
|
XmppAxolotlMessage axolotlMessage = buildHeader(message.getConversation());
|
||||||
|
|
||||||
if (axolotlMessage != null) {
|
if (axolotlMessage != null) {
|
||||||
final String content;
|
final String content;
|
||||||
|
@ -913,11 +957,11 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void prepareKeyTransportMessage(final Contact contact, final OnMessageCreatedCallback onMessageCreatedCallback) {
|
public void prepareKeyTransportMessage(final Conversation conversation, final OnMessageCreatedCallback onMessageCreatedCallback) {
|
||||||
executor.execute(new Runnable() {
|
executor.execute(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
XmppAxolotlMessage axolotlMessage = buildHeader(contact);
|
XmppAxolotlMessage axolotlMessage = buildHeader(conversation);
|
||||||
onMessageCreatedCallback.run(axolotlMessage);
|
onMessageCreatedCallback.run(axolotlMessage);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -659,8 +659,8 @@ public class Conversation extends AbstractEntity implements Blockable {
|
||||||
final AxolotlService axolotlService = getAccount().getAxolotlService();
|
final AxolotlService axolotlService = getAccount().getAxolotlService();
|
||||||
int next = this.getIntAttribute(ATTRIBUTE_NEXT_ENCRYPTION, -1);
|
int next = this.getIntAttribute(ATTRIBUTE_NEXT_ENCRYPTION, -1);
|
||||||
if (next == -1) {
|
if (next == -1) {
|
||||||
if (Config.X509_VERIFICATION && mode == MODE_SINGLE) {
|
if (Config.X509_VERIFICATION) {
|
||||||
if (axolotlService != null && axolotlService.isContactAxolotlCapable(getContact())) {
|
if (axolotlService != null && axolotlService.isConversationAxolotlCapable(this)) {
|
||||||
return Message.ENCRYPTION_AXOLOTL;
|
return Message.ENCRYPTION_AXOLOTL;
|
||||||
} else {
|
} else {
|
||||||
return Message.ENCRYPTION_NONE;
|
return Message.ENCRYPTION_NONE;
|
||||||
|
@ -673,16 +673,20 @@ public class Conversation extends AbstractEntity implements Blockable {
|
||||||
next = outgoing;
|
next = outgoing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!Config.supportUnencrypted()
|
|
||||||
&& (mode == MODE_SINGLE || Config.supportOpenPgpOnly())
|
if (!Config.supportUnencrypted() && next <= 0) {
|
||||||
&& next <= 0) {
|
if (Config.supportOmemo()
|
||||||
if (Config.supportOmemo() && (axolotlService != null && axolotlService.isContactAxolotlCapable(getContact()) || !Config.multipleEncryptionChoices())) {
|
&& (axolotlService != null && axolotlService.isConversationAxolotlCapable(this) || !Config.multipleEncryptionChoices())) {
|
||||||
return Message.ENCRYPTION_AXOLOTL;
|
return Message.ENCRYPTION_AXOLOTL;
|
||||||
} else if (Config.supportOtr()) {
|
} else if (Config.supportOtr() && mode == MODE_SINGLE) {
|
||||||
return Message.ENCRYPTION_OTR;
|
return Message.ENCRYPTION_OTR;
|
||||||
} else if (Config.supportOpenPgp()) {
|
} else if (Config.supportOpenPgp()
|
||||||
|
&& (mode == MODE_SINGLE) || !Config.multipleEncryptionChoices()) {
|
||||||
return Message.ENCRYPTION_PGP;
|
return Message.ENCRYPTION_PGP;
|
||||||
}
|
}
|
||||||
|
} else if (next == Message.ENCRYPTION_AXOLOTL
|
||||||
|
&& (!Config.supportOmemo() || axolotlService == null || !axolotlService.isConversationAxolotlCapable(this))) {
|
||||||
|
next = Message.ENCRYPTION_NONE;
|
||||||
}
|
}
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,11 @@ import android.annotation.SuppressLint;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import eu.siacs.conversations.R;
|
import eu.siacs.conversations.R;
|
||||||
import eu.siacs.conversations.xmpp.forms.Data;
|
import eu.siacs.conversations.xmpp.forms.Data;
|
||||||
|
@ -245,6 +247,7 @@ public class MucOptions {
|
||||||
|
|
||||||
private Account account;
|
private Account account;
|
||||||
private final Map<String, User> users = Collections.synchronizedMap(new LinkedHashMap<String, User>());
|
private final Map<String, User> users = Collections.synchronizedMap(new LinkedHashMap<String, User>());
|
||||||
|
private final Set<Jid> members = Collections.synchronizedSet(new HashSet<Jid>());
|
||||||
private List<String> features = new ArrayList<>();
|
private List<String> features = new ArrayList<>();
|
||||||
private Data form = new Data();
|
private Data form = new Data();
|
||||||
private Conversation conversation;
|
private Conversation conversation;
|
||||||
|
@ -501,4 +504,12 @@ public class MucOptions {
|
||||||
public Conversation getConversation() {
|
public Conversation getConversation() {
|
||||||
return this.conversation;
|
return this.conversation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void putMember(Jid jid) {
|
||||||
|
members.add(jid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Jid> getMembers() {
|
||||||
|
return new ArrayList<>(members);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -335,4 +335,11 @@ public class IqGenerator extends AbstractGenerator {
|
||||||
enable.addChild(data);
|
enable.addChild(data);
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IqPacket queryAffiliation(Conversation conversation, String affiliation) {
|
||||||
|
IqPacket packet = new IqPacket(IqPacket.TYPE.GET);
|
||||||
|
packet.setTo(conversation.getJid().toBareJid());
|
||||||
|
packet.query("http://jabber.org/protocol/muc#admin").addChild("item").setAttribute("affiliation",affiliation);
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,7 +103,7 @@ public class MessageParser extends AbstractParser implements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Message parseAxolotlChat(Element axolotlMessage, Jid from, String id, Conversation conversation, int status) {
|
private Message parseAxolotlChat(Element axolotlMessage, Jid from, Conversation conversation, int status) {
|
||||||
Message finishedMessage = null;
|
Message finishedMessage = null;
|
||||||
AxolotlService service = conversation.getAccount().getAxolotlService();
|
AxolotlService service = conversation.getAccount().getAxolotlService();
|
||||||
XmppAxolotlMessage xmppAxolotlMessage = XmppAxolotlMessage.fromElement(axolotlMessage, from.toBareJid());
|
XmppAxolotlMessage xmppAxolotlMessage = XmppAxolotlMessage.fromElement(axolotlMessage, from.toBareJid());
|
||||||
|
@ -357,7 +357,17 @@ public class MessageParser extends AbstractParser implements
|
||||||
} else if (pgpEncrypted != null && Config.supportOpenPgp()) {
|
} else if (pgpEncrypted != null && Config.supportOpenPgp()) {
|
||||||
message = new Message(conversation, pgpEncrypted, Message.ENCRYPTION_PGP, status);
|
message = new Message(conversation, pgpEncrypted, Message.ENCRYPTION_PGP, status);
|
||||||
} else if (axolotlEncrypted != null && Config.supportOmemo()) {
|
} else if (axolotlEncrypted != null && Config.supportOmemo()) {
|
||||||
message = parseAxolotlChat(axolotlEncrypted, from, remoteMsgId, conversation, status);
|
Jid origin;
|
||||||
|
if (conversation.getMode() == Conversation.MODE_MULTI) {
|
||||||
|
origin = conversation.getMucOptions().getTrueCounterpart(counterpart.getResourcepart());
|
||||||
|
if (origin == null) {
|
||||||
|
Log.d(Config.LOGTAG,"axolotl message in non anonymous conference received");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
origin = from;
|
||||||
|
}
|
||||||
|
message = parseAxolotlChat(axolotlEncrypted, origin, conversation, status);
|
||||||
if (message == null) {
|
if (message == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,10 +64,14 @@ public class PresenceParser extends AbstractParser implements
|
||||||
Element item = x.findChild("item");
|
Element item = x.findChild("item");
|
||||||
if (item != null && !from.isBareJid()) {
|
if (item != null && !from.isBareJid()) {
|
||||||
mucOptions.setError(MucOptions.Error.NONE);
|
mucOptions.setError(MucOptions.Error.NONE);
|
||||||
MucOptions.User user = new MucOptions.User(mucOptions,from);
|
MucOptions.User user = new MucOptions.User(mucOptions, from);
|
||||||
user.setAffiliation(item.getAttribute("affiliation"));
|
user.setAffiliation(item.getAttribute("affiliation"));
|
||||||
user.setRole(item.getAttribute("role"));
|
user.setRole(item.getAttribute("role"));
|
||||||
user.setJid(item.getAttributeAsJid("jid"));
|
Jid real = item.getAttributeAsJid("jid");
|
||||||
|
if (real != null) {
|
||||||
|
user.setJid(real);
|
||||||
|
mucOptions.putMember(real.toBareJid());
|
||||||
|
}
|
||||||
if (codes.contains(MucOptions.STATUS_CODE_SELF_PRESENCE) || packet.getFrom().equals(mucOptions.getConversation().getJid())) {
|
if (codes.contains(MucOptions.STATUS_CODE_SELF_PRESENCE) || packet.getFrom().equals(mucOptions.getConversation().getJid())) {
|
||||||
mucOptions.setOnline();
|
mucOptions.setOnline();
|
||||||
mucOptions.setSelf(user);
|
mucOptions.setSelf(user);
|
||||||
|
|
|
@ -1784,6 +1784,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
||||||
Account account = conversation.getAccount();
|
Account account = conversation.getAccount();
|
||||||
final String nick = conversation.getMucOptions().getProposedNick();
|
final String nick = conversation.getMucOptions().getProposedNick();
|
||||||
final Jid joinJid = conversation.getMucOptions().createJoinJid(nick);
|
final Jid joinJid = conversation.getMucOptions().createJoinJid(nick);
|
||||||
|
final MucOptions mucOptions = conversation.getMucOptions();
|
||||||
Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": joining conversation " + joinJid.toString());
|
Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": joining conversation " + joinJid.toString());
|
||||||
PresencePacket packet = new PresencePacket();
|
PresencePacket packet = new PresencePacket();
|
||||||
packet.setFrom(conversation.getAccount().getJid());
|
packet.setFrom(conversation.getAccount().getJid());
|
||||||
|
@ -1793,7 +1794,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
||||||
x.addChild("password").setContent(conversation.getMucOptions().getPassword());
|
x.addChild("password").setContent(conversation.getMucOptions().getPassword());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conversation.getMucOptions().mamSupport()) {
|
if (mucOptions.mamSupport()) {
|
||||||
// Use MAM instead of the limited muc history to get history
|
// Use MAM instead of the limited muc history to get history
|
||||||
x.addChild("history").setAttribute("maxchars", "0");
|
x.addChild("history").setAttribute("maxchars", "0");
|
||||||
} else {
|
} else {
|
||||||
|
@ -1812,9 +1813,13 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
||||||
conversation.setContactJid(joinJid);
|
conversation.setContactJid(joinJid);
|
||||||
databaseBackend.updateConversation(conversation);
|
databaseBackend.updateConversation(conversation);
|
||||||
}
|
}
|
||||||
if (conversation.getMucOptions().mamSupport()) {
|
|
||||||
|
if (mucOptions.mamSupport()) {
|
||||||
getMessageArchiveService().catchupMUC(conversation);
|
getMessageArchiveService().catchupMUC(conversation);
|
||||||
}
|
}
|
||||||
|
if (mucOptions.membersOnly() && mucOptions.nonanonymous()) {
|
||||||
|
fetchConferenceMembers(conversation);
|
||||||
|
}
|
||||||
sendUnsentMessages(conversation);
|
sendUnsentMessages(conversation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1838,6 +1843,37 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void fetchConferenceMembers(final Conversation conversation) {
|
||||||
|
final Account account = conversation.getAccount();
|
||||||
|
final String[] affiliations = {"member","admin","owner"};
|
||||||
|
OnIqPacketReceived callback = new OnIqPacketReceived() {
|
||||||
|
|
||||||
|
private int i = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onIqPacketReceived(Account account, IqPacket packet) {
|
||||||
|
Element query = packet.query("http://jabber.org/protocol/muc#admin");
|
||||||
|
if (packet.getType() == IqPacket.TYPE.RESULT && query != null) {
|
||||||
|
for(Element child : query.getChildren()) {
|
||||||
|
if ("item".equals(child.getName())) {
|
||||||
|
conversation.getMucOptions().putMember(child.getAttributeAsJid("jid"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": could not request affiliation "+affiliations[i]+" in "+conversation.getJid().toBareJid());
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
if (i >= affiliations.length) {
|
||||||
|
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": retrieved members for "+conversation.getJid().toBareJid()+": "+conversation.getMucOptions().getMembers());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for(String affiliation : affiliations) {
|
||||||
|
sendIqPacket(account, mIqGenerator.queryAffiliation(conversation, affiliation), callback);
|
||||||
|
}
|
||||||
|
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": fetching members for "+conversation.getName());
|
||||||
|
}
|
||||||
|
|
||||||
public void providePasswordForMuc(Conversation conversation, String password) {
|
public void providePasswordForMuc(Conversation conversation, String password) {
|
||||||
if (conversation.getMode() == Conversation.MODE_MULTI) {
|
if (conversation.getMode() == Conversation.MODE_MULTI) {
|
||||||
conversation.getMucOptions().setPassword(password);
|
conversation.getMucOptions().setPassword(password);
|
||||||
|
|
|
@ -408,7 +408,7 @@ public class ConversationActivity extends XmppActivity
|
||||||
menuContactDetails.setVisible(false);
|
menuContactDetails.setVisible(false);
|
||||||
menuAttach.setVisible(getSelectedConversation().getAccount().httpUploadAvailable() && getSelectedConversation().getMucOptions().participating());
|
menuAttach.setVisible(getSelectedConversation().getAccount().httpUploadAvailable() && getSelectedConversation().getMucOptions().participating());
|
||||||
menuInviteContact.setVisible(getSelectedConversation().getMucOptions().canInvite());
|
menuInviteContact.setVisible(getSelectedConversation().getMucOptions().canInvite());
|
||||||
menuSecure.setVisible(Config.supportOpenPgp() && Config.multipleEncryptionChoices()); //only if pgp is supported we have a choice
|
menuSecure.setVisible((Config.supportOpenPgp() || Config.supportOmemo()) && Config.multipleEncryptionChoices()); //only if pgp is supported we have a choice
|
||||||
} else {
|
} else {
|
||||||
menuMucDetails.setVisible(false);
|
menuMucDetails.setVisible(false);
|
||||||
menuSecure.setVisible(Config.multipleEncryptionChoices());
|
menuSecure.setVisible(Config.multipleEncryptionChoices());
|
||||||
|
@ -856,8 +856,8 @@ public class ConversationActivity extends XmppActivity
|
||||||
axolotl.setVisible(Config.supportOmemo());
|
axolotl.setVisible(Config.supportOmemo());
|
||||||
if (conversation.getMode() == Conversation.MODE_MULTI) {
|
if (conversation.getMode() == Conversation.MODE_MULTI) {
|
||||||
otr.setVisible(false);
|
otr.setVisible(false);
|
||||||
axolotl.setVisible(false);
|
}
|
||||||
} else if (!conversation.getAccount().getAxolotlService().isContactAxolotlCapable(conversation.getContact())) {
|
if (!conversation.getAccount().getAxolotlService().isConversationAxolotlCapable(conversation)) {
|
||||||
axolotl.setEnabled(false);
|
axolotl.setEnabled(false);
|
||||||
}
|
}
|
||||||
switch (conversation.getNextEncryption()) {
|
switch (conversation.getNextEncryption()) {
|
||||||
|
@ -1530,18 +1530,21 @@ public class ConversationActivity extends XmppActivity
|
||||||
|
|
||||||
protected boolean trustKeysIfNeeded(int requestCode, int attachmentChoice) {
|
protected boolean trustKeysIfNeeded(int requestCode, int attachmentChoice) {
|
||||||
AxolotlService axolotlService = mSelectedConversation.getAccount().getAxolotlService();
|
AxolotlService axolotlService = mSelectedConversation.getAccount().getAxolotlService();
|
||||||
Contact contact = mSelectedConversation.getContact();
|
final List<Jid> targets = axolotlService.getCryptoTargets(mSelectedConversation);
|
||||||
boolean hasUndecidedOwn = !axolotlService.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED).isEmpty();
|
boolean hasUndecidedOwn = !axolotlService.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED).isEmpty();
|
||||||
boolean hasUndecidedContact = !axolotlService.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED,contact).isEmpty();
|
boolean hasUndecidedContacts = !axolotlService.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED, targets).isEmpty();
|
||||||
boolean hasPendingKeys = !axolotlService.findDevicesWithoutSession(mSelectedConversation).isEmpty();
|
boolean hasPendingKeys = !axolotlService.findDevicesWithoutSession(mSelectedConversation).isEmpty();
|
||||||
boolean hasNoTrustedKeys = axolotlService.getNumTrustedKeys(mSelectedConversation.getContact()) == 0;
|
boolean hasNoTrustedKeys = axolotlService.anyTargetHasNoTrustedKeys(targets);
|
||||||
if(hasUndecidedOwn || hasUndecidedContact || hasPendingKeys || hasNoTrustedKeys) {
|
if(hasUndecidedOwn || hasUndecidedContacts || hasPendingKeys || hasNoTrustedKeys) {
|
||||||
axolotlService.createSessionsIfNeeded(mSelectedConversation);
|
axolotlService.createSessionsIfNeeded(mSelectedConversation);
|
||||||
Intent intent = new Intent(getApplicationContext(), TrustKeysActivity.class);
|
Intent intent = new Intent(getApplicationContext(), TrustKeysActivity.class);
|
||||||
intent.putExtra("contact", mSelectedConversation.getContact().getJid().toBareJid().toString());
|
String[] contacts = new String[targets.size()];
|
||||||
|
for(int i = 0; i < contacts.length; ++i) {
|
||||||
|
contacts[i] = targets.get(i).toString();
|
||||||
|
}
|
||||||
|
intent.putExtra("contacts", contacts);
|
||||||
intent.putExtra(EXTRA_ACCOUNT, mSelectedConversation.getAccount().getJid().toBareJid().toString());
|
intent.putExtra(EXTRA_ACCOUNT, mSelectedConversation.getAccount().getJid().toBareJid().toString());
|
||||||
intent.putExtra("choice", attachmentChoice);
|
intent.putExtra("choice", attachmentChoice);
|
||||||
intent.putExtra("has_no_trusted", hasNoTrustedKeys);
|
|
||||||
startActivityForResult(intent, requestCode);
|
startActivityForResult(intent, requestCode);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -12,7 +12,9 @@ import android.widget.Toast;
|
||||||
|
|
||||||
import org.whispersystems.libaxolotl.IdentityKey;
|
import org.whispersystems.libaxolotl.IdentityKey;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -20,32 +22,28 @@ import eu.siacs.conversations.R;
|
||||||
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
|
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
|
||||||
import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession;
|
import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession;
|
||||||
import eu.siacs.conversations.entities.Account;
|
import eu.siacs.conversations.entities.Account;
|
||||||
import eu.siacs.conversations.entities.Contact;
|
|
||||||
import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;
|
import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;
|
||||||
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
|
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
|
||||||
import eu.siacs.conversations.xmpp.jid.Jid;
|
import eu.siacs.conversations.xmpp.jid.Jid;
|
||||||
|
|
||||||
public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdated {
|
public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdated {
|
||||||
private Jid accountJid;
|
private Jid accountJid;
|
||||||
private Jid contactJid;
|
private List<Jid> contactJids;
|
||||||
|
|
||||||
private Contact contact;
|
|
||||||
private Account mAccount;
|
private Account mAccount;
|
||||||
private TextView keyErrorMessage;
|
private TextView keyErrorMessage;
|
||||||
private LinearLayout keyErrorMessageCard;
|
private LinearLayout keyErrorMessageCard;
|
||||||
private TextView ownKeysTitle;
|
private TextView ownKeysTitle;
|
||||||
private LinearLayout ownKeys;
|
private LinearLayout ownKeys;
|
||||||
private LinearLayout ownKeysCard;
|
private LinearLayout ownKeysCard;
|
||||||
private TextView foreignKeysTitle;
|
|
||||||
private LinearLayout foreignKeys;
|
private LinearLayout foreignKeys;
|
||||||
private LinearLayout foreignKeysCard;
|
|
||||||
private Button mSaveButton;
|
private Button mSaveButton;
|
||||||
private Button mCancelButton;
|
private Button mCancelButton;
|
||||||
|
|
||||||
private AxolotlService.FetchStatus lastFetchReport = AxolotlService.FetchStatus.SUCCESS;
|
private AxolotlService.FetchStatus lastFetchReport = AxolotlService.FetchStatus.SUCCESS;
|
||||||
|
|
||||||
private final Map<String, Boolean> ownKeysToTrust = new HashMap<>();
|
private final Map<String, Boolean> ownKeysToTrust = new HashMap<>();
|
||||||
private final Map<String, Boolean> foreignKeysToTrust = new HashMap<>();
|
private final Map<Jid,Map<String, Boolean>> foreignKeysToTrust = new HashMap<>();
|
||||||
|
|
||||||
private final OnClickListener mSaveButtonListener = new OnClickListener() {
|
private final OnClickListener mSaveButtonListener = new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -69,15 +67,6 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate
|
||||||
populateView();
|
populateView();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getShareableUri() {
|
|
||||||
if (contact != null) {
|
|
||||||
return contact.getShareableUri();
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(final Bundle savedInstanceState) {
|
protected void onCreate(final Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
@ -86,9 +75,13 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate
|
||||||
this.accountJid = Jid.fromString(getIntent().getExtras().getString(EXTRA_ACCOUNT));
|
this.accountJid = Jid.fromString(getIntent().getExtras().getString(EXTRA_ACCOUNT));
|
||||||
} catch (final InvalidJidException ignored) {
|
} catch (final InvalidJidException ignored) {
|
||||||
}
|
}
|
||||||
|
this.contactJids = new ArrayList<>();
|
||||||
|
for(String jid : getIntent().getStringArrayExtra("contacts")) {
|
||||||
try {
|
try {
|
||||||
this.contactJid = Jid.fromString(getIntent().getExtras().getString("contact"));
|
this.contactJids.add(Jid.fromString(jid));
|
||||||
} catch (final InvalidJidException ignored) {
|
} catch (InvalidJidException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
keyErrorMessageCard = (LinearLayout) findViewById(R.id.key_error_message_card);
|
keyErrorMessageCard = (LinearLayout) findViewById(R.id.key_error_message_card);
|
||||||
|
@ -96,9 +89,7 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate
|
||||||
ownKeysTitle = (TextView) findViewById(R.id.own_keys_title);
|
ownKeysTitle = (TextView) findViewById(R.id.own_keys_title);
|
||||||
ownKeys = (LinearLayout) findViewById(R.id.own_keys_details);
|
ownKeys = (LinearLayout) findViewById(R.id.own_keys_details);
|
||||||
ownKeysCard = (LinearLayout) findViewById(R.id.own_keys_card);
|
ownKeysCard = (LinearLayout) findViewById(R.id.own_keys_card);
|
||||||
foreignKeysTitle = (TextView) findViewById(R.id.foreign_keys_title);
|
foreignKeys = (LinearLayout) findViewById(R.id.foreign_keys);
|
||||||
foreignKeys = (LinearLayout) findViewById(R.id.foreign_keys_details);
|
|
||||||
foreignKeysCard = (LinearLayout) findViewById(R.id.foreign_keys_card);
|
|
||||||
mCancelButton = (Button) findViewById(R.id.cancel_button);
|
mCancelButton = (Button) findViewById(R.id.cancel_button);
|
||||||
mCancelButton.setOnClickListener(mCancelButtonListener);
|
mCancelButton.setOnClickListener(mCancelButtonListener);
|
||||||
mSaveButton = (Button) findViewById(R.id.save_button);
|
mSaveButton = (Button) findViewById(R.id.save_button);
|
||||||
|
@ -119,7 +110,7 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate
|
||||||
boolean hasForeignKeys = false;
|
boolean hasForeignKeys = false;
|
||||||
for(final String fingerprint : ownKeysToTrust.keySet()) {
|
for(final String fingerprint : ownKeysToTrust.keySet()) {
|
||||||
hasOwnKeys = true;
|
hasOwnKeys = true;
|
||||||
addFingerprintRowWithListeners(ownKeys, contact.getAccount(), fingerprint, false,
|
addFingerprintRowWithListeners(ownKeys, mAccount, fingerprint, false,
|
||||||
XmppAxolotlSession.Trust.fromBoolean(ownKeysToTrust.get(fingerprint)), false,
|
XmppAxolotlSession.Trust.fromBoolean(ownKeysToTrust.get(fingerprint)), false,
|
||||||
new CompoundButton.OnCheckedChangeListener() {
|
new CompoundButton.OnCheckedChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -132,14 +123,22 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
for(final String fingerprint : foreignKeysToTrust.keySet()) {
|
|
||||||
|
synchronized (this.foreignKeysToTrust) {
|
||||||
|
for (Map.Entry<Jid, Map<String, Boolean>> entry : foreignKeysToTrust.entrySet()) {
|
||||||
|
final LinearLayout layout = (LinearLayout) getLayoutInflater().inflate(R.layout.keys_card, foreignKeys, false);
|
||||||
|
final TextView header = (TextView) layout.findViewById(R.id.foreign_keys_title);
|
||||||
|
final LinearLayout keysContainer = (LinearLayout) layout.findViewById(R.id.foreign_keys_details);
|
||||||
|
header.setText(entry.getKey().toString());
|
||||||
|
final Map<String, Boolean> fingerprints = entry.getValue();
|
||||||
|
for (final String fingerprint : fingerprints.keySet()) {
|
||||||
hasForeignKeys = true;
|
hasForeignKeys = true;
|
||||||
addFingerprintRowWithListeners(foreignKeys, contact.getAccount(), fingerprint, false,
|
addFingerprintRowWithListeners(keysContainer, mAccount, fingerprint, false,
|
||||||
XmppAxolotlSession.Trust.fromBoolean(foreignKeysToTrust.get(fingerprint)), false,
|
XmppAxolotlSession.Trust.fromBoolean(fingerprints.get(fingerprint)), false,
|
||||||
new CompoundButton.OnCheckedChangeListener() {
|
new CompoundButton.OnCheckedChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||||
foreignKeysToTrust.put(fingerprint, isChecked);
|
fingerprints.put(fingerprint, isChecked);
|
||||||
lockOrUnlockAsNeeded();
|
lockOrUnlockAsNeeded();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -147,15 +146,13 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
foreignKeys.addView(layout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(hasOwnKeys) {
|
|
||||||
ownKeysTitle.setText(accountJid.toString());
|
ownKeysTitle.setText(accountJid.toString());
|
||||||
ownKeysCard.setVisibility(View.VISIBLE);
|
ownKeysCard.setVisibility(hasOwnKeys ? View.VISIBLE : View.GONE);
|
||||||
}
|
foreignKeys.setVisibility(hasForeignKeys ? View.VISIBLE : View.GONE);
|
||||||
if(hasForeignKeys) {
|
|
||||||
foreignKeysTitle.setText(contactJid.toString());
|
|
||||||
foreignKeysCard.setVisibility(View.VISIBLE);
|
|
||||||
}
|
|
||||||
if(hasPendingKeyFetches()) {
|
if(hasPendingKeyFetches()) {
|
||||||
setFetching();
|
setFetching();
|
||||||
lock();
|
lock();
|
||||||
|
@ -163,13 +160,15 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate
|
||||||
if (!hasForeignKeys && hasNoOtherTrustedKeys()) {
|
if (!hasForeignKeys && hasNoOtherTrustedKeys()) {
|
||||||
keyErrorMessageCard.setVisibility(View.VISIBLE);
|
keyErrorMessageCard.setVisibility(View.VISIBLE);
|
||||||
if (lastFetchReport == AxolotlService.FetchStatus.ERROR
|
if (lastFetchReport == AxolotlService.FetchStatus.ERROR
|
||||||
|| contact.getAccount().getAxolotlService().fetchMapHasErrors(contact)) {
|
|| mAccount.getAxolotlService().fetchMapHasErrors(contactJids)) {
|
||||||
keyErrorMessage.setText(R.string.error_no_keys_to_trust_server_error);
|
keyErrorMessage.setText(R.string.error_no_keys_to_trust_server_error);
|
||||||
} else {
|
} else {
|
||||||
keyErrorMessage.setText(R.string.error_no_keys_to_trust);
|
keyErrorMessage.setText(R.string.error_no_keys_to_trust);
|
||||||
}
|
}
|
||||||
ownKeys.removeAllViews(); ownKeysCard.setVisibility(View.GONE);
|
ownKeys.removeAllViews();
|
||||||
foreignKeys.removeAllViews(); foreignKeysCard.setVisibility(View.GONE);
|
ownKeysCard.setVisibility(View.GONE);
|
||||||
|
foreignKeys.removeAllViews();
|
||||||
|
foreignKeys.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
lockOrUnlockAsNeeded();
|
lockOrUnlockAsNeeded();
|
||||||
setDone();
|
setDone();
|
||||||
|
@ -178,45 +177,56 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate
|
||||||
|
|
||||||
private boolean reloadFingerprints() {
|
private boolean reloadFingerprints() {
|
||||||
ownKeysToTrust.clear();
|
ownKeysToTrust.clear();
|
||||||
foreignKeysToTrust.clear();
|
|
||||||
AxolotlService service = this.mAccount.getAxolotlService();
|
AxolotlService service = this.mAccount.getAxolotlService();
|
||||||
Set<IdentityKey> ownKeysSet = service.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED);
|
Set<IdentityKey> ownKeysSet = service.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED);
|
||||||
Set<IdentityKey> foreignKeysSet = service.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED, contact);
|
|
||||||
if (hasNoOtherTrustedKeys() && ownKeysSet.size() == 0) {
|
|
||||||
foreignKeysSet.addAll(service.getKeysWithTrust(XmppAxolotlSession.Trust.UNTRUSTED, contact));
|
|
||||||
}
|
|
||||||
for(final IdentityKey identityKey : ownKeysSet) {
|
for(final IdentityKey identityKey : ownKeysSet) {
|
||||||
if(!ownKeysToTrust.containsKey(identityKey)) {
|
if(!ownKeysToTrust.containsKey(identityKey)) {
|
||||||
ownKeysToTrust.put(identityKey.getFingerprint().replaceAll("\\s", ""), false);
|
ownKeysToTrust.put(identityKey.getFingerprint().replaceAll("\\s", ""), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(final IdentityKey identityKey : foreignKeysSet) {
|
synchronized (this.foreignKeysToTrust) {
|
||||||
if(!foreignKeysToTrust.containsKey(identityKey)) {
|
foreignKeysToTrust.clear();
|
||||||
foreignKeysToTrust.put(identityKey.getFingerprint().replaceAll("\\s", ""), false);
|
for (Jid jid : contactJids) {
|
||||||
|
Set<IdentityKey> foreignKeysSet = service.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED, jid);
|
||||||
|
if (hasNoOtherTrustedKeys(jid) && ownKeysSet.size() == 0) {
|
||||||
|
foreignKeysSet.addAll(service.getKeysWithTrust(XmppAxolotlSession.Trust.UNTRUSTED, jid));
|
||||||
|
}
|
||||||
|
Map<String, Boolean> foreignFingerprints = new HashMap<>();
|
||||||
|
for (final IdentityKey identityKey : foreignKeysSet) {
|
||||||
|
if (!foreignFingerprints.containsKey(identityKey)) {
|
||||||
|
foreignFingerprints.put(identityKey.getFingerprint().replaceAll("\\s", ""), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ownKeysSet.size() + foreignKeysSet.size() > 0;
|
if (foreignFingerprints.size() > 0) {
|
||||||
|
foreignKeysToTrust.put(jid, foreignFingerprints);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ownKeysSet.size() + foreignKeysToTrust.size() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBackendConnected() {
|
public void onBackendConnected() {
|
||||||
if ((accountJid != null) && (contactJid != null)) {
|
if (accountJid != null) {
|
||||||
this.mAccount = xmppConnectionService.findAccountByJid(accountJid);
|
this.mAccount = xmppConnectionService.findAccountByJid(accountJid);
|
||||||
if (this.mAccount == null) {
|
if (this.mAccount == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.contact = this.mAccount.getRoster().getContact(contactJid);
|
|
||||||
reloadFingerprints();
|
reloadFingerprints();
|
||||||
populateView();
|
populateView();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasNoOtherTrustedKeys() {
|
private boolean hasNoOtherTrustedKeys() {
|
||||||
|
return mAccount == null || mAccount.getAxolotlService().anyTargetHasNoTrustedKeys(contactJids);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasNoOtherTrustedKeys(Jid contact) {
|
||||||
return mAccount == null || mAccount.getAxolotlService().getNumTrustedKeys(contact) == 0;
|
return mAccount == null || mAccount.getAxolotlService().getNumTrustedKeys(contact) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasPendingKeyFetches() {
|
private boolean hasPendingKeyFetches() {
|
||||||
return mAccount != null && contact != null && mAccount.getAxolotlService().hasPendingKeyFetches(mAccount,contact);
|
return mAccount != null && mAccount.getAxolotlService().hasPendingKeyFetches(mAccount, contactJids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -262,14 +272,18 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate
|
||||||
|
|
||||||
private void commitTrusts() {
|
private void commitTrusts() {
|
||||||
for(final String fingerprint :ownKeysToTrust.keySet()) {
|
for(final String fingerprint :ownKeysToTrust.keySet()) {
|
||||||
contact.getAccount().getAxolotlService().setFingerprintTrust(
|
mAccount.getAxolotlService().setFingerprintTrust(
|
||||||
fingerprint,
|
fingerprint,
|
||||||
XmppAxolotlSession.Trust.fromBoolean(ownKeysToTrust.get(fingerprint)));
|
XmppAxolotlSession.Trust.fromBoolean(ownKeysToTrust.get(fingerprint)));
|
||||||
}
|
}
|
||||||
for(final String fingerprint:foreignKeysToTrust.keySet()) {
|
synchronized (this.foreignKeysToTrust) {
|
||||||
contact.getAccount().getAxolotlService().setFingerprintTrust(
|
for (Map<String, Boolean> value : foreignKeysToTrust.values()) {
|
||||||
|
for (final String fingerprint : value.keySet()) {
|
||||||
|
mAccount.getAxolotlService().setFingerprintTrust(
|
||||||
fingerprint,
|
fingerprint,
|
||||||
XmppAxolotlSession.Trust.fromBoolean(foreignKeysToTrust.get(fingerprint)));
|
XmppAxolotlSession.Trust.fromBoolean(value.get(fingerprint)));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,12 +298,18 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate
|
||||||
}
|
}
|
||||||
|
|
||||||
private void lockOrUnlockAsNeeded() {
|
private void lockOrUnlockAsNeeded() {
|
||||||
if (hasNoOtherTrustedKeys() && !foreignKeysToTrust.values().contains(true)){
|
synchronized (this.foreignKeysToTrust) {
|
||||||
|
for (Jid jid : contactJids) {
|
||||||
|
Map<String, Boolean> fingerprints = foreignKeysToTrust.get(jid);
|
||||||
|
if (hasNoOtherTrustedKeys(jid) && (fingerprints == null || !fingerprints.values().contains(true))) {
|
||||||
lock();
|
lock();
|
||||||
} else {
|
return;
|
||||||
unlock();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
unlock();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private void setDone() {
|
private void setDone() {
|
||||||
mSaveButton.setText(getString(R.string.done));
|
mSaveButton.setText(getString(R.string.done));
|
||||||
|
|
|
@ -218,7 +218,7 @@ public class JingleConnection implements Transferable {
|
||||||
public void init(final Message message) {
|
public void init(final Message message) {
|
||||||
if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL) {
|
if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL) {
|
||||||
Conversation conversation = message.getConversation();
|
Conversation conversation = message.getConversation();
|
||||||
conversation.getAccount().getAxolotlService().prepareKeyTransportMessage(conversation.getContact(), new OnMessageCreatedCallback() {
|
conversation.getAccount().getAxolotlService().prepareKeyTransportMessage(conversation, new OnMessageCreatedCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void run(XmppAxolotlMessage xmppAxolotlMessage) {
|
public void run(XmppAxolotlMessage xmppAxolotlMessage) {
|
||||||
if (xmppAxolotlMessage != null) {
|
if (xmppAxolotlMessage != null) {
|
||||||
|
|
|
@ -80,34 +80,11 @@
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/foreign_keys_card"
|
android:id="@+id/foreign_keys"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="@dimen/activity_horizontal_margin"
|
android:visibility="gone"
|
||||||
android:layout_marginRight="@dimen/activity_horizontal_margin"
|
|
||||||
android:layout_marginTop="@dimen/activity_vertical_margin"
|
|
||||||
android:layout_marginBottom="@dimen/activity_vertical_margin"
|
|
||||||
android:background="@drawable/infocard_border"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:padding="@dimen/infocard_padding"
|
|
||||||
android:visibility="gone">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/foreign_keys_title"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textColor="@color/black87"
|
|
||||||
android:textSize="?attr/TextSizeHeadline"
|
|
||||||
android:textStyle="bold"/>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/foreign_keys_details"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:divider="?android:dividerHorizontal"
|
|
||||||
android:showDividers="middle"
|
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/foreign_keys_card"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="@dimen/activity_horizontal_margin"
|
||||||
|
android:layout_marginRight="@dimen/activity_horizontal_margin"
|
||||||
|
android:layout_marginTop="@dimen/activity_vertical_margin"
|
||||||
|
android:layout_marginBottom="@dimen/activity_vertical_margin"
|
||||||
|
android:background="@drawable/infocard_border"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="@dimen/infocard_padding">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/foreign_keys_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/black87"
|
||||||
|
android:textSize="?attr/TextSizeHeadline"
|
||||||
|
android:textStyle="bold"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/foreign_keys_details"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:divider="?android:dividerHorizontal"
|
||||||
|
android:showDividers="middle"
|
||||||
|
android:orientation="vertical">
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
Loading…
Reference in New Issue