Ask for key trust when sending messages
If the contact (or the own account) has keys that have UNDECIDED trust, we now drop the user into the new TrustKeysActivity, where they have to decide for each new key whether it should be TRUSTED or UNTRUSTED.
This commit is contained in:
parent
ec0aff4ed7
commit
14010bf5a6
|
@ -130,6 +130,10 @@
|
||||||
<data android:mimeType="image/*" />
|
<data android:mimeType="image/*" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name=".ui.TrustKeysActivity"
|
||||||
|
android:label="@string/trust_keys"
|
||||||
|
android:windowSoftInputMode="stateAlwaysHidden"/>
|
||||||
<activity
|
<activity
|
||||||
android:name="de.duenndns.ssl.MemorizingActivity"
|
android:name="de.duenndns.ssl.MemorizingActivity"
|
||||||
android:theme="@style/ConversationsTheme"
|
android:theme="@style/ConversationsTheme"
|
||||||
|
|
|
@ -115,6 +115,10 @@ public class AxolotlService {
|
||||||
return "Untrusted";
|
return "Untrusted";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Trust fromBoolean(Boolean trusted) {
|
||||||
|
return trusted?TRUSTED:UNTRUSTED;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private static IdentityKeyPair generateIdentityKeyPair() {
|
private static IdentityKeyPair generateIdentityKeyPair() {
|
||||||
|
@ -275,6 +279,10 @@ public class AxolotlService {
|
||||||
mXmppConnectionService.databaseBackend.setIdentityKeyTrust(account, fingerprint, trust);
|
mXmppConnectionService.databaseBackend.setIdentityKeyTrust(account, fingerprint, trust);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<IdentityKey> getContactUndecidedKeys(String bareJid) {
|
||||||
|
return mXmppConnectionService.databaseBackend.loadIdentityKeys(account, bareJid, Trust.UNDECIDED);
|
||||||
|
}
|
||||||
|
|
||||||
// --------------------------------------
|
// --------------------------------------
|
||||||
// SessionStore
|
// SessionStore
|
||||||
// --------------------------------------
|
// --------------------------------------
|
||||||
|
@ -658,6 +666,14 @@ public class AxolotlService {
|
||||||
return axolotlStore.getIdentityKeyPair().getPublicKey();
|
return axolotlStore.getIdentityKeyPair().getPublicKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<IdentityKey> getPendingKeys() {
|
||||||
|
return axolotlStore.getContactUndecidedKeys(account.getJid().toBareJid().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<IdentityKey> getPendingKeys(Contact contact) {
|
||||||
|
return axolotlStore.getContactUndecidedKeys(contact.getJid().toBareJid().toString());
|
||||||
|
}
|
||||||
|
|
||||||
private AxolotlAddress getAddressForJid(Jid jid) {
|
private AxolotlAddress getAddressForJid(Jid jid) {
|
||||||
return new AxolotlAddress(jid.toString(), 0);
|
return new AxolotlAddress(jid.toString(), 0);
|
||||||
}
|
}
|
||||||
|
@ -852,14 +868,32 @@ public class AxolotlService {
|
||||||
axolotlStore.setFingerprintTrust(fingerprint, trust);
|
axolotlStore.setFingerprintTrust(fingerprint, trust);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void buildSessionFromPEP(final Conversation conversation, final AxolotlAddress address) {
|
private void buildSessionFromPEP(final Conversation conversation, final AxolotlAddress address, final boolean flushWaitingQueueAfterFetch) {
|
||||||
Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Building new sesstion for " + address.getDeviceId());
|
Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Building new sesstion for " + address.getDeviceId());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
IqPacket bundlesPacket = mXmppConnectionService.getIqGenerator().retrieveBundlesForDevice(
|
IqPacket bundlesPacket = mXmppConnectionService.getIqGenerator().retrieveBundlesForDevice(
|
||||||
Jid.fromString(address.getName()), address.getDeviceId());
|
Jid.fromString(address.getName()), address.getDeviceId());
|
||||||
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Retrieving bundle: " + bundlesPacket);
|
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Retrieving bundle: " + bundlesPacket);
|
||||||
mXmppConnectionService.sendIqPacket(account, bundlesPacket, new OnIqPacketReceived() {
|
mXmppConnectionService.sendIqPacket(account, bundlesPacket, new OnIqPacketReceived() {
|
||||||
|
private void finish() {
|
||||||
|
AxolotlAddress ownAddress = new AxolotlAddress(conversation.getAccount().getJid().toBareJid().toString(),0);
|
||||||
|
AxolotlAddress foreignAddress = new AxolotlAddress(conversation.getJid().toBareJid().toString(),0);
|
||||||
|
if (!fetchStatusMap.getAll(ownAddress).containsValue(FetchStatus.PENDING)
|
||||||
|
&& !fetchStatusMap.getAll(foreignAddress).containsValue(FetchStatus.PENDING)) {
|
||||||
|
if (flushWaitingQueueAfterFetch) {
|
||||||
|
conversation.findUnsentMessagesWithEncryption(Message.ENCRYPTION_AXOLOTL,
|
||||||
|
new Conversation.OnMessageFound() {
|
||||||
|
@Override
|
||||||
|
public void onMessageFound(Message message) {
|
||||||
|
processSending(message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
mXmppConnectionService.newKeysAvailable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onIqPacketReceived(Account account, IqPacket packet) {
|
public void onIqPacketReceived(Account account, IqPacket packet) {
|
||||||
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Received preKey IQ packet, processing...");
|
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Received preKey IQ packet, processing...");
|
||||||
|
@ -869,6 +903,7 @@ public class AxolotlService {
|
||||||
if (preKeyBundleList.isEmpty() || bundle == null) {
|
if (preKeyBundleList.isEmpty() || bundle == null) {
|
||||||
Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account)+"preKey IQ packet invalid: " + packet);
|
Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account)+"preKey IQ packet invalid: " + packet);
|
||||||
fetchStatusMap.put(address, FetchStatus.ERROR);
|
fetchStatusMap.put(address, FetchStatus.ERROR);
|
||||||
|
finish();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Random random = new Random();
|
Random random = new Random();
|
||||||
|
@ -876,6 +911,7 @@ public class AxolotlService {
|
||||||
if (preKey == null) {
|
if (preKey == null) {
|
||||||
//should never happen
|
//should never happen
|
||||||
fetchStatusMap.put(address, FetchStatus.ERROR);
|
fetchStatusMap.put(address, FetchStatus.ERROR);
|
||||||
|
finish();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -898,18 +934,7 @@ public class AxolotlService {
|
||||||
fetchStatusMap.put(address, FetchStatus.ERROR);
|
fetchStatusMap.put(address, FetchStatus.ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
AxolotlAddress ownAddress = new AxolotlAddress(conversation.getAccount().getJid().toBareJid().toString(),0);
|
finish();
|
||||||
AxolotlAddress foreignAddress = new AxolotlAddress(conversation.getJid().toBareJid().toString(),0);
|
|
||||||
if (!fetchStatusMap.getAll(ownAddress).containsValue(FetchStatus.PENDING)
|
|
||||||
&& !fetchStatusMap.getAll(foreignAddress).containsValue(FetchStatus.PENDING)) {
|
|
||||||
conversation.findUnsentMessagesWithEncryption(Message.ENCRYPTION_AXOLOTL,
|
|
||||||
new Conversation.OnMessageFound() {
|
|
||||||
@Override
|
|
||||||
public void onMessageFound(Message message) {
|
|
||||||
processSending(message);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (InvalidJidException e) {
|
} catch (InvalidJidException e) {
|
||||||
|
@ -917,48 +942,75 @@ public class AxolotlService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean createSessionsIfNeeded(Conversation conversation) {
|
public Set<AxolotlAddress> findDevicesWithoutSession(final Conversation conversation) {
|
||||||
boolean newSessions = false;
|
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Finding devices without session for " + conversation.getContact().getJid().toBareJid());
|
||||||
Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Creating axolotl sessions if needed...");
|
|
||||||
Jid contactJid = conversation.getContact().getJid().toBareJid();
|
Jid contactJid = conversation.getContact().getJid().toBareJid();
|
||||||
Set<AxolotlAddress> addresses = new HashSet<>();
|
Set<AxolotlAddress> addresses = new HashSet<>();
|
||||||
if(deviceIds.get(contactJid) != null) {
|
if(deviceIds.get(contactJid) != null) {
|
||||||
for(Integer foreignId:this.deviceIds.get(contactJid)) {
|
for(Integer foreignId:this.deviceIds.get(contactJid)) {
|
||||||
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Found device "+account.getJid().toBareJid()+":"+foreignId);
|
AxolotlAddress address = new AxolotlAddress(contactJid.toString(), foreignId);
|
||||||
addresses.add(new AxolotlAddress(contactJid.toString(), foreignId));
|
if(sessions.get(address) == null) {
|
||||||
|
IdentityKey identityKey = axolotlStore.loadSession(address).getSessionState().getRemoteIdentityKey();
|
||||||
|
if ( identityKey != null ) {
|
||||||
|
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Already have session for " + address.toString() + ", adding to cache...");
|
||||||
|
XmppAxolotlSession session = new XmppAxolotlSession(account, axolotlStore, address, identityKey.getFingerprint().replaceAll("\\s", ""));
|
||||||
|
sessions.put(address, session);
|
||||||
|
} else {
|
||||||
|
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Found device " + account.getJid().toBareJid() + ":" + foreignId);
|
||||||
|
addresses.add(new AxolotlAddress(contactJid.toString(), foreignId));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} 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!");
|
||||||
}
|
}
|
||||||
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Checking own account "+account.getJid().toBareJid());
|
|
||||||
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())) {
|
||||||
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Found device "+account.getJid().toBareJid()+":"+ownId);
|
AxolotlAddress address = new AxolotlAddress(account.getJid().toBareJid().toString(), ownId);
|
||||||
addresses.add(new AxolotlAddress(account.getJid().toBareJid().toString(), ownId));
|
if(sessions.get(address) == null) {
|
||||||
}
|
IdentityKey identityKey = axolotlStore.loadSession(address).getSessionState().getRemoteIdentityKey();
|
||||||
}
|
if ( identityKey != null ) {
|
||||||
for (AxolotlAddress address : addresses) {
|
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Already have session for " + address.toString() + ", adding to cache...");
|
||||||
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Processing device: " + address.toString());
|
XmppAxolotlSession session = new XmppAxolotlSession(account, axolotlStore, address, identityKey.getFingerprint().replaceAll("\\s", ""));
|
||||||
FetchStatus status = fetchStatusMap.get(address);
|
sessions.put(address, session);
|
||||||
XmppAxolotlSession session = sessions.get(address);
|
} else {
|
||||||
if ( session == null && ( status == null || status == FetchStatus.ERROR) ) {
|
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Found device " + account.getJid().toBareJid() + ":" + ownId);
|
||||||
IdentityKey identityKey = axolotlStore.loadSession(address).getSessionState().getRemoteIdentityKey();
|
addresses.add(new AxolotlAddress(account.getJid().toBareJid().toString(), ownId));
|
||||||
if ( identityKey != null ) {
|
}
|
||||||
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Already have session for " + address.toString() + ", adding to cache...");
|
|
||||||
session = new XmppAxolotlSession(account, axolotlStore, address, identityKey.getFingerprint().replaceAll("\\s", ""));
|
|
||||||
sessions.put(address, session);
|
|
||||||
} else {
|
|
||||||
fetchStatusMap.put(address, FetchStatus.PENDING);
|
|
||||||
this.buildSessionFromPEP(conversation, address);
|
|
||||||
newSessions = true;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Already have session for " + address.toString());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return addresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean createSessionsIfNeeded(final Conversation conversation, final boolean flushWaitingQueueAfterFetch) {
|
||||||
|
Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Creating axolotl sessions if needed...");
|
||||||
|
boolean newSessions = false;
|
||||||
|
Set<AxolotlAddress> addresses = findDevicesWithoutSession(conversation);
|
||||||
|
for (AxolotlAddress address : addresses) {
|
||||||
|
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Processing device: " + address.toString());
|
||||||
|
FetchStatus status = fetchStatusMap.get(address);
|
||||||
|
if ( status == null || status == FetchStatus.ERROR ) {
|
||||||
|
fetchStatusMap.put(address, FetchStatus.PENDING);
|
||||||
|
this.buildSessionFromPEP(conversation, address, flushWaitingQueueAfterFetch);
|
||||||
|
newSessions = true;
|
||||||
|
} else {
|
||||||
|
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Already fetching bundle for " + address.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return newSessions;
|
return newSessions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasPendingKeyFetches(Conversation conversation) {
|
||||||
|
AxolotlAddress ownAddress = new AxolotlAddress(account.getJid().toBareJid().toString(),0);
|
||||||
|
AxolotlAddress foreignAddress = new AxolotlAddress(conversation.getJid().toBareJid().toString(),0);
|
||||||
|
return fetchStatusMap.getAll(ownAddress).containsValue(FetchStatus.PENDING)
|
||||||
|
||fetchStatusMap.getAll(foreignAddress).containsValue(FetchStatus.PENDING);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public XmppAxolotlMessage encrypt(Message message ){
|
public XmppAxolotlMessage encrypt(Message message ){
|
||||||
final String content;
|
final String content;
|
||||||
|
@ -1013,10 +1065,9 @@ public class AxolotlService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void prepareMessage(Message message) {
|
public void prepareMessage(final Message message) {
|
||||||
if (!messageCache.containsKey(message.getUuid())) {
|
if (!messageCache.containsKey(message.getUuid())) {
|
||||||
boolean newSessions = createSessionsIfNeeded(message.getConversation());
|
boolean newSessions = createSessionsIfNeeded(message.getConversation(), true);
|
||||||
|
|
||||||
if (!newSessions) {
|
if (!newSessions) {
|
||||||
this.processSending(message);
|
this.processSending(message);
|
||||||
}
|
}
|
||||||
|
|
|
@ -834,10 +834,19 @@ public class DatabaseBackend extends SQLiteOpenHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<IdentityKey> loadIdentityKeys(Account account, String name) {
|
public Set<IdentityKey> loadIdentityKeys(Account account, String name) {
|
||||||
|
return loadIdentityKeys(account, name, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<IdentityKey> loadIdentityKeys(Account account, String name, AxolotlService.SQLiteAxolotlStore.Trust trust) {
|
||||||
Set<IdentityKey> identityKeys = new HashSet<>();
|
Set<IdentityKey> identityKeys = new HashSet<>();
|
||||||
Cursor cursor = getIdentityKeyCursor(account, name, false);
|
Cursor cursor = getIdentityKeyCursor(account, name, false);
|
||||||
|
|
||||||
while(cursor.moveToNext()) {
|
while(cursor.moveToNext()) {
|
||||||
|
if ( trust != null &&
|
||||||
|
cursor.getInt(cursor.getColumnIndex(AxolotlService.SQLiteAxolotlStore.TRUSTED))
|
||||||
|
!= trust.ordinal()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
identityKeys.add(new IdentityKey(Base64.decode(cursor.getString(cursor.getColumnIndex(AxolotlService.SQLiteAxolotlStore.KEY)),Base64.DEFAULT),0));
|
identityKeys.add(new IdentityKey(Base64.decode(cursor.getString(cursor.getColumnIndex(AxolotlService.SQLiteAxolotlStore.KEY)),Base64.DEFAULT),0));
|
||||||
} catch (InvalidKeyException e) {
|
} catch (InvalidKeyException e) {
|
||||||
|
|
|
@ -85,6 +85,7 @@ import eu.siacs.conversations.xmpp.OnContactStatusChanged;
|
||||||
import eu.siacs.conversations.xmpp.OnIqPacketReceived;
|
import eu.siacs.conversations.xmpp.OnIqPacketReceived;
|
||||||
import eu.siacs.conversations.xmpp.OnMessageAcknowledged;
|
import eu.siacs.conversations.xmpp.OnMessageAcknowledged;
|
||||||
import eu.siacs.conversations.xmpp.OnMessagePacketReceived;
|
import eu.siacs.conversations.xmpp.OnMessagePacketReceived;
|
||||||
|
import eu.siacs.conversations.xmpp.OnNewKeysAvailable;
|
||||||
import eu.siacs.conversations.xmpp.OnPresencePacketReceived;
|
import eu.siacs.conversations.xmpp.OnPresencePacketReceived;
|
||||||
import eu.siacs.conversations.xmpp.OnStatusChanged;
|
import eu.siacs.conversations.xmpp.OnStatusChanged;
|
||||||
import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
|
import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
|
||||||
|
@ -307,6 +308,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
||||||
private int rosterChangedListenerCount = 0;
|
private int rosterChangedListenerCount = 0;
|
||||||
private OnMucRosterUpdate mOnMucRosterUpdate = null;
|
private OnMucRosterUpdate mOnMucRosterUpdate = null;
|
||||||
private int mucRosterChangedListenerCount = 0;
|
private int mucRosterChangedListenerCount = 0;
|
||||||
|
private OnNewKeysAvailable mOnNewKeysAvailable = null;
|
||||||
|
private int newKeysAvailableListenerCount = 0;
|
||||||
private SecureRandom mRandom;
|
private SecureRandom mRandom;
|
||||||
private OpenPgpServiceConnection pgpServiceConnection;
|
private OpenPgpServiceConnection pgpServiceConnection;
|
||||||
private PgpEngine mPgpEngine = null;
|
private PgpEngine mPgpEngine = null;
|
||||||
|
@ -1344,17 +1347,17 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
||||||
switchToForeground();
|
switchToForeground();
|
||||||
}
|
}
|
||||||
this.mOnUpdateBlocklist = listener;
|
this.mOnUpdateBlocklist = listener;
|
||||||
if (this.updateBlocklistListenerCount < 2) {
|
if (this.newKeysAvailableListenerCount < 2) {
|
||||||
this.updateBlocklistListenerCount++;
|
this.newKeysAvailableListenerCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeOnUpdateBlocklistListener() {
|
public void removeOnUpdateBlocklistListener() {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
this.updateBlocklistListenerCount--;
|
this.newKeysAvailableListenerCount--;
|
||||||
if (this.updateBlocklistListenerCount <= 0) {
|
if (this.newKeysAvailableListenerCount <= 0) {
|
||||||
this.updateBlocklistListenerCount = 0;
|
this.newKeysAvailableListenerCount = 0;
|
||||||
this.mOnUpdateBlocklist = null;
|
this.mOnUpdateBlocklist = null;
|
||||||
if (checkListeners()) {
|
if (checkListeners()) {
|
||||||
switchToBackground();
|
switchToBackground();
|
||||||
|
@ -1363,6 +1366,30 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setOnNewKeysAvailableListener(final OnNewKeysAvailable listener) {
|
||||||
|
synchronized (this) {
|
||||||
|
if (checkListeners()) {
|
||||||
|
switchToForeground();
|
||||||
|
}
|
||||||
|
this.mOnNewKeysAvailable = listener;
|
||||||
|
if (this.newKeysAvailableListenerCount < 2) {
|
||||||
|
this.newKeysAvailableListenerCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeOnNewKeysAvailableListener() {
|
||||||
|
synchronized (this) {
|
||||||
|
this.newKeysAvailableListenerCount--;
|
||||||
|
if (this.newKeysAvailableListenerCount <= 0) {
|
||||||
|
this.newKeysAvailableListenerCount = 0;
|
||||||
|
this.mOnNewKeysAvailable = null;
|
||||||
|
if (checkListeners()) {
|
||||||
|
switchToBackground();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
public void setOnMucRosterUpdateListener(OnMucRosterUpdate listener) {
|
public void setOnMucRosterUpdateListener(OnMucRosterUpdate listener) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (checkListeners()) {
|
if (checkListeners()) {
|
||||||
|
@ -1393,7 +1420,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
||||||
&& this.mOnConversationUpdate == null
|
&& this.mOnConversationUpdate == null
|
||||||
&& this.mOnRosterUpdate == null
|
&& this.mOnRosterUpdate == null
|
||||||
&& this.mOnUpdateBlocklist == null
|
&& this.mOnUpdateBlocklist == null
|
||||||
&& this.mOnShowErrorToast == null);
|
&& this.mOnShowErrorToast == null
|
||||||
|
&& this.mOnNewKeysAvailable == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void switchToForeground() {
|
private void switchToForeground() {
|
||||||
|
@ -2281,6 +2309,12 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void newKeysAvailable() {
|
||||||
|
if(mOnNewKeysAvailable != null) {
|
||||||
|
mOnNewKeysAvailable.onNewKeysAvailable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Account findAccountByJid(final Jid accountJid) {
|
public Account findAccountByJid(final Jid accountJid) {
|
||||||
for (Account account : this.accounts) {
|
for (Account account : this.accounts) {
|
||||||
if (account.getJid().toBareJid().equals(accountJid.toBareJid())) {
|
if (account.getJid().toBareJid().equals(accountJid.toBareJid())) {
|
||||||
|
|
|
@ -65,11 +65,14 @@ public class ConversationActivity extends XmppActivity
|
||||||
public static final int REQUEST_SEND_MESSAGE = 0x0201;
|
public static final int REQUEST_SEND_MESSAGE = 0x0201;
|
||||||
public static final int REQUEST_DECRYPT_PGP = 0x0202;
|
public static final int REQUEST_DECRYPT_PGP = 0x0202;
|
||||||
public static final int REQUEST_ENCRYPT_MESSAGE = 0x0207;
|
public static final int REQUEST_ENCRYPT_MESSAGE = 0x0207;
|
||||||
|
public static final int REQUEST_TRUST_KEYS_TEXT = 0x0208;
|
||||||
|
public static final int REQUEST_TRUST_KEYS_MENU = 0x0209;
|
||||||
public static final int ATTACHMENT_CHOICE_CHOOSE_IMAGE = 0x0301;
|
public static final int ATTACHMENT_CHOICE_CHOOSE_IMAGE = 0x0301;
|
||||||
public static final int ATTACHMENT_CHOICE_TAKE_PHOTO = 0x0302;
|
public static final int ATTACHMENT_CHOICE_TAKE_PHOTO = 0x0302;
|
||||||
public static final int ATTACHMENT_CHOICE_CHOOSE_FILE = 0x0303;
|
public static final int ATTACHMENT_CHOICE_CHOOSE_FILE = 0x0303;
|
||||||
public static final int ATTACHMENT_CHOICE_RECORD_VOICE = 0x0304;
|
public static final int ATTACHMENT_CHOICE_RECORD_VOICE = 0x0304;
|
||||||
public static final int ATTACHMENT_CHOICE_LOCATION = 0x0305;
|
public static final int ATTACHMENT_CHOICE_LOCATION = 0x0305;
|
||||||
|
public static final int ATTACHMENT_CHOICE_INVALID = 0x0306;
|
||||||
private static final String STATE_OPEN_CONVERSATION = "state_open_conversation";
|
private static final String STATE_OPEN_CONVERSATION = "state_open_conversation";
|
||||||
private static final String STATE_PANEL_OPEN = "state_panel_open";
|
private static final String STATE_PANEL_OPEN = "state_panel_open";
|
||||||
private static final String STATE_PENDING_URI = "state_pending_uri";
|
private static final String STATE_PENDING_URI = "state_pending_uri";
|
||||||
|
@ -79,6 +82,7 @@ public class ConversationActivity extends XmppActivity
|
||||||
final private List<Uri> mPendingImageUris = new ArrayList<>();
|
final private List<Uri> mPendingImageUris = new ArrayList<>();
|
||||||
final private List<Uri> mPendingFileUris = new ArrayList<>();
|
final private List<Uri> mPendingFileUris = new ArrayList<>();
|
||||||
private Uri mPendingGeoUri = null;
|
private Uri mPendingGeoUri = null;
|
||||||
|
private boolean forbidProcessingPendings = false;
|
||||||
|
|
||||||
private View mContentView;
|
private View mContentView;
|
||||||
|
|
||||||
|
@ -401,7 +405,7 @@ public class ConversationActivity extends XmppActivity
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void selectPresenceToAttachFile(final int attachmentChoice, final int encryption) {
|
protected void selectPresenceToAttachFile(final int attachmentChoice, final int encryption) {
|
||||||
final Conversation conversation = getSelectedConversation();
|
final Conversation conversation = getSelectedConversation();
|
||||||
final Account account = conversation.getAccount();
|
final Account account = conversation.getAccount();
|
||||||
final OnPresenceSelected callback = new OnPresenceSelected() {
|
final OnPresenceSelected callback = new OnPresenceSelected() {
|
||||||
|
@ -537,7 +541,9 @@ public class ConversationActivity extends XmppActivity
|
||||||
showInstallPgpDialog();
|
showInstallPgpDialog();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
selectPresenceToAttachFile(attachmentChoice,encryption);
|
if (encryption != Message.ENCRYPTION_AXOLOTL || !trustKeysIfNeeded(REQUEST_TRUST_KEYS_MENU, attachmentChoice)) {
|
||||||
|
selectPresenceToAttachFile(attachmentChoice, encryption);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -962,18 +968,23 @@ public class ConversationActivity extends XmppActivity
|
||||||
this.mConversationFragment.reInit(getSelectedConversation());
|
this.mConversationFragment.reInit(getSelectedConversation());
|
||||||
}
|
}
|
||||||
|
|
||||||
for(Iterator<Uri> i = mPendingImageUris.iterator(); i.hasNext(); i.remove()) {
|
if(!forbidProcessingPendings) {
|
||||||
attachImageToConversation(getSelectedConversation(),i.next());
|
for (Iterator<Uri> i = mPendingImageUris.iterator(); i.hasNext(); i.remove()) {
|
||||||
}
|
Uri foo = i.next();
|
||||||
|
attachImageToConversation(getSelectedConversation(), foo);
|
||||||
|
}
|
||||||
|
|
||||||
for(Iterator<Uri> i = mPendingFileUris.iterator(); i.hasNext(); i.remove()) {
|
for (Iterator<Uri> i = mPendingFileUris.iterator(); i.hasNext(); i.remove()) {
|
||||||
attachFileToConversation(getSelectedConversation(),i.next());
|
attachFileToConversation(getSelectedConversation(), i.next());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mPendingGeoUri != null) {
|
if (mPendingGeoUri != null) {
|
||||||
attachLocationToConversation(getSelectedConversation(), mPendingGeoUri);
|
attachLocationToConversation(getSelectedConversation(), mPendingGeoUri);
|
||||||
mPendingGeoUri = null;
|
mPendingGeoUri = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
forbidProcessingPendings = false;
|
||||||
|
|
||||||
ExceptionHelper.checkForCrash(this, this.xmppConnectionService);
|
ExceptionHelper.checkForCrash(this, this.xmppConnectionService);
|
||||||
setIntent(new Intent());
|
setIntent(new Intent());
|
||||||
}
|
}
|
||||||
|
@ -1083,6 +1094,9 @@ public class ConversationActivity extends XmppActivity
|
||||||
attachLocationToConversation(getSelectedConversation(), mPendingGeoUri);
|
attachLocationToConversation(getSelectedConversation(), mPendingGeoUri);
|
||||||
this.mPendingGeoUri = null;
|
this.mPendingGeoUri = null;
|
||||||
}
|
}
|
||||||
|
} else if (requestCode == REQUEST_TRUST_KEYS_TEXT || requestCode == REQUEST_TRUST_KEYS_MENU) {
|
||||||
|
this.forbidProcessingPendings = !xmppConnectionServiceBound;
|
||||||
|
mConversationFragment.onActivityResult(requestCode, resultCode, data);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mPendingImageUris.clear();
|
mPendingImageUris.clear();
|
||||||
|
@ -1235,6 +1249,26 @@ public class ConversationActivity extends XmppActivity
|
||||||
return getPreferences().getBoolean("indicate_received", false);
|
return getPreferences().getBoolean("indicate_received", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean trustKeysIfNeeded(int requestCode) {
|
||||||
|
return trustKeysIfNeeded(requestCode, ATTACHMENT_CHOICE_INVALID);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean trustKeysIfNeeded(int requestCode, int attachmentChoice) {
|
||||||
|
AxolotlService axolotlService = mSelectedConversation.getAccount().getAxolotlService();
|
||||||
|
if(!axolotlService.getPendingKeys(mSelectedConversation.getContact()).isEmpty()
|
||||||
|
|| !axolotlService.findDevicesWithoutSession(mSelectedConversation).isEmpty()) {
|
||||||
|
axolotlService.createSessionsIfNeeded(mSelectedConversation, false);
|
||||||
|
Intent intent = new Intent(getApplicationContext(), TrustKeysActivity.class);
|
||||||
|
intent.putExtra("contact", mSelectedConversation.getContact().getJid().toBareJid().toString());
|
||||||
|
intent.putExtra("account", mSelectedConversation.getAccount().getJid().toBareJid().toString());
|
||||||
|
intent.putExtra("choice", attachmentChoice);
|
||||||
|
startActivityForResult(intent, requestCode);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void refreshUiReal() {
|
protected void refreshUiReal() {
|
||||||
updateConversationList();
|
updateConversationList();
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package eu.siacs.conversations.ui;
|
package eu.siacs.conversations.ui;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
|
@ -11,6 +12,7 @@ import android.content.IntentSender;
|
||||||
import android.content.IntentSender.SendIntentException;
|
import android.content.IntentSender.SendIntentException;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.ContextMenu;
|
import android.view.ContextMenu;
|
||||||
import android.view.ContextMenu.ContextMenuInfo;
|
import android.view.ContextMenu.ContextMenuInfo;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
|
@ -43,6 +45,7 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
import eu.siacs.conversations.Config;
|
import eu.siacs.conversations.Config;
|
||||||
import eu.siacs.conversations.R;
|
import eu.siacs.conversations.R;
|
||||||
import eu.siacs.conversations.crypto.PgpEngine;
|
import eu.siacs.conversations.crypto.PgpEngine;
|
||||||
|
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
|
||||||
import eu.siacs.conversations.entities.Account;
|
import eu.siacs.conversations.entities.Account;
|
||||||
import eu.siacs.conversations.entities.Contact;
|
import eu.siacs.conversations.entities.Contact;
|
||||||
import eu.siacs.conversations.entities.Conversation;
|
import eu.siacs.conversations.entities.Conversation;
|
||||||
|
@ -304,7 +307,9 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
|
||||||
} else if (conversation.getNextEncryption(activity.forceEncryption()) == Message.ENCRYPTION_PGP) {
|
} else if (conversation.getNextEncryption(activity.forceEncryption()) == Message.ENCRYPTION_PGP) {
|
||||||
sendPgpMessage(message);
|
sendPgpMessage(message);
|
||||||
} else if (conversation.getNextEncryption(activity.forceEncryption()) == Message.ENCRYPTION_AXOLOTL) {
|
} else if (conversation.getNextEncryption(activity.forceEncryption()) == Message.ENCRYPTION_AXOLOTL) {
|
||||||
sendAxolotlMessage(message);
|
if(!activity.trustKeysIfNeeded(ConversationActivity.REQUEST_TRUST_KEYS_TEXT)) {
|
||||||
|
sendAxolotlMessage(message);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
sendPlainTextMessage(message);
|
sendPlainTextMessage(message);
|
||||||
}
|
}
|
||||||
|
@ -1128,7 +1133,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
|
||||||
protected void sendAxolotlMessage(final Message message) {
|
protected void sendAxolotlMessage(final Message message) {
|
||||||
final ConversationActivity activity = (ConversationActivity) getActivity();
|
final ConversationActivity activity = (ConversationActivity) getActivity();
|
||||||
final XmppConnectionService xmppService = activity.xmppConnectionService;
|
final XmppConnectionService xmppService = activity.xmppConnectionService;
|
||||||
//message.setCounterpart(conversation.getNextCounterpart());
|
|
||||||
xmppService.sendMessage(message);
|
xmppService.sendMessage(message);
|
||||||
messageSent();
|
messageSent();
|
||||||
}
|
}
|
||||||
|
@ -1195,4 +1199,19 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
|
||||||
updateSendButton();
|
updateSendButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityResult(int requestCode, int resultCode,
|
||||||
|
final Intent data) {
|
||||||
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
|
if (requestCode == ConversationActivity.REQUEST_TRUST_KEYS_TEXT) {
|
||||||
|
final String body = mEditMessage.getText().toString();
|
||||||
|
Message message = new Message(conversation, body, conversation.getNextEncryption(activity.forceEncryption()));
|
||||||
|
sendAxolotlMessage(message);
|
||||||
|
} else if (requestCode == ConversationActivity.REQUEST_TRUST_KEYS_MENU) {
|
||||||
|
int choice = data.getIntExtra("choice", ConversationActivity.ATTACHMENT_CHOICE_INVALID);
|
||||||
|
activity.selectPresenceToAttachFile(choice, conversation.getNextEncryption(activity.forceEncryption()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,237 @@
|
||||||
|
package eu.siacs.conversations.ui;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.CompoundButton;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import org.whispersystems.libaxolotl.IdentityKey;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.Config;
|
||||||
|
import eu.siacs.conversations.R;
|
||||||
|
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
|
||||||
|
import eu.siacs.conversations.crypto.axolotl.AxolotlService.SQLiteAxolotlStore.Trust;
|
||||||
|
import eu.siacs.conversations.entities.Account;
|
||||||
|
import eu.siacs.conversations.entities.Contact;
|
||||||
|
import eu.siacs.conversations.entities.Conversation;
|
||||||
|
import eu.siacs.conversations.xmpp.OnNewKeysAvailable;
|
||||||
|
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
|
||||||
|
import eu.siacs.conversations.xmpp.jid.Jid;
|
||||||
|
|
||||||
|
public class TrustKeysActivity extends XmppActivity implements OnNewKeysAvailable {
|
||||||
|
private Jid accountJid;
|
||||||
|
private Jid contactJid;
|
||||||
|
|
||||||
|
private Contact contact;
|
||||||
|
private TextView ownKeysTitle;
|
||||||
|
private LinearLayout ownKeys;
|
||||||
|
private LinearLayout ownKeysCard;
|
||||||
|
private TextView foreignKeysTitle;
|
||||||
|
private LinearLayout foreignKeys;
|
||||||
|
private LinearLayout foreignKeysCard;
|
||||||
|
private Button mSaveButton;
|
||||||
|
private Button mCancelButton;
|
||||||
|
|
||||||
|
private final Map<IdentityKey, Boolean> ownKeysToTrust = new HashMap<>();
|
||||||
|
private final Map<IdentityKey, Boolean> foreignKeysToTrust = new HashMap<>();
|
||||||
|
|
||||||
|
private final OnClickListener mSaveButtonListener = new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
commitTrusts();
|
||||||
|
Intent data = new Intent();
|
||||||
|
data.putExtra("choice", getIntent().getIntExtra("choice", ConversationActivity.ATTACHMENT_CHOICE_INVALID));
|
||||||
|
setResult(RESULT_OK, data);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final OnClickListener mCancelButtonListener = new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
setResult(RESULT_CANCELED);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void refreshUiReal() {
|
||||||
|
invalidateOptionsMenu();
|
||||||
|
populateView();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getShareableUri() {
|
||||||
|
if (contact != null) {
|
||||||
|
return contact.getShareableUri();
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(final Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_trust_keys);
|
||||||
|
try {
|
||||||
|
this.accountJid = Jid.fromString(getIntent().getExtras().getString("account"));
|
||||||
|
} catch (final InvalidJidException ignored) {
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
this.contactJid = Jid.fromString(getIntent().getExtras().getString("contact"));
|
||||||
|
} catch (final InvalidJidException ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ownKeysTitle = (TextView) findViewById(R.id.own_keys_title);
|
||||||
|
ownKeys = (LinearLayout) findViewById(R.id.own_keys_details);
|
||||||
|
ownKeysCard = (LinearLayout) findViewById(R.id.own_keys_card);
|
||||||
|
foreignKeysTitle = (TextView) findViewById(R.id.foreign_keys_title);
|
||||||
|
foreignKeys = (LinearLayout) findViewById(R.id.foreign_keys_details);
|
||||||
|
foreignKeysCard = (LinearLayout) findViewById(R.id.foreign_keys_card);
|
||||||
|
mCancelButton = (Button) findViewById(R.id.cancel_button);
|
||||||
|
mCancelButton.setOnClickListener(mCancelButtonListener);
|
||||||
|
mSaveButton = (Button) findViewById(R.id.save_button);
|
||||||
|
mSaveButton.setOnClickListener(mSaveButtonListener);
|
||||||
|
|
||||||
|
|
||||||
|
if (getActionBar() != null) {
|
||||||
|
getActionBar().setHomeButtonEnabled(true);
|
||||||
|
getActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void populateView() {
|
||||||
|
setTitle(getString(R.string.trust_keys));
|
||||||
|
ownKeys.removeAllViews();
|
||||||
|
foreignKeys.removeAllViews();
|
||||||
|
boolean hasOwnKeys = false;
|
||||||
|
boolean hasForeignKeys = false;
|
||||||
|
for(final IdentityKey identityKey : ownKeysToTrust.keySet()) {
|
||||||
|
hasOwnKeys = true;
|
||||||
|
addFingerprintRowWithListeners(ownKeys, contact.getAccount(), identityKey,
|
||||||
|
Trust.fromBoolean(ownKeysToTrust.get(identityKey)), false,
|
||||||
|
new CompoundButton.OnCheckedChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||||
|
ownKeysToTrust.put(identityKey, isChecked);
|
||||||
|
refreshUi();
|
||||||
|
xmppConnectionService.updateAccountUi();
|
||||||
|
xmppConnectionService.updateConversationUi();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
for(final IdentityKey identityKey : foreignKeysToTrust.keySet()) {
|
||||||
|
hasForeignKeys = true;
|
||||||
|
addFingerprintRowWithListeners(foreignKeys, contact.getAccount(), identityKey,
|
||||||
|
Trust.fromBoolean(foreignKeysToTrust.get(identityKey)), false,
|
||||||
|
new CompoundButton.OnCheckedChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||||
|
foreignKeysToTrust.put(identityKey, isChecked);
|
||||||
|
refreshUi();
|
||||||
|
xmppConnectionService.updateAccountUi();
|
||||||
|
xmppConnectionService.updateConversationUi();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(hasOwnKeys) {
|
||||||
|
ownKeysTitle.setText(accountJid.toString());
|
||||||
|
ownKeysCard.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
if(hasForeignKeys) {
|
||||||
|
foreignKeysTitle.setText(contactJid.toString());
|
||||||
|
foreignKeysCard.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void getFingerprints(final Account account) {
|
||||||
|
Set<IdentityKey> ownKeysSet = account.getAxolotlService().getPendingKeys();
|
||||||
|
for(final IdentityKey identityKey : ownKeysSet) {
|
||||||
|
if(!ownKeysToTrust.containsKey(identityKey)) {
|
||||||
|
ownKeysToTrust.put(identityKey, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Set<IdentityKey> foreignKeysSet = account.getAxolotlService().getPendingKeys(contact);
|
||||||
|
for(final IdentityKey identityKey : foreignKeysSet) {
|
||||||
|
if(!foreignKeysToTrust.containsKey(identityKey)) {
|
||||||
|
foreignKeysToTrust.put(identityKey, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackendConnected() {
|
||||||
|
if ((accountJid != null) && (contactJid != null)) {
|
||||||
|
final Account account = xmppConnectionService
|
||||||
|
.findAccountByJid(accountJid);
|
||||||
|
if (account == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.contact = account.getRoster().getContact(contactJid);
|
||||||
|
ownKeysToTrust.clear();
|
||||||
|
foreignKeysToTrust.clear();
|
||||||
|
getFingerprints(account);
|
||||||
|
|
||||||
|
Conversation conversation = xmppConnectionService.findOrCreateConversation(account, contactJid, false);
|
||||||
|
if(account.getAxolotlService().hasPendingKeyFetches(conversation)) {
|
||||||
|
lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
populateView();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNewKeysAvailable() {
|
||||||
|
runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
final Account account = xmppConnectionService
|
||||||
|
.findAccountByJid(accountJid);
|
||||||
|
unlock();
|
||||||
|
getFingerprints(account);
|
||||||
|
refreshUi();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void commitTrusts() {
|
||||||
|
for(IdentityKey identityKey:ownKeysToTrust.keySet()) {
|
||||||
|
contact.getAccount().getAxolotlService().setFingerprintTrust(
|
||||||
|
identityKey.getFingerprint().replaceAll("\\s", ""),
|
||||||
|
Trust.fromBoolean(ownKeysToTrust.get(identityKey)));
|
||||||
|
}
|
||||||
|
for(IdentityKey identityKey:foreignKeysToTrust.keySet()) {
|
||||||
|
contact.getAccount().getAxolotlService().setFingerprintTrust(
|
||||||
|
identityKey.getFingerprint().replaceAll("\\s", ""),
|
||||||
|
Trust.fromBoolean(foreignKeysToTrust.get(identityKey)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void unlock() {
|
||||||
|
mSaveButton.setEnabled(true);
|
||||||
|
mSaveButton.setText(getString(R.string.done));
|
||||||
|
mSaveButton.setTextColor(getPrimaryTextColor());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void lock() {
|
||||||
|
mSaveButton.setEnabled(false);
|
||||||
|
mSaveButton.setText(getString(R.string.fetching_keys));
|
||||||
|
mSaveButton.setTextColor(getSecondaryTextColor());
|
||||||
|
}
|
||||||
|
}
|
|
@ -84,6 +84,7 @@ import eu.siacs.conversations.services.XmppConnectionService.XmppConnectionBinde
|
||||||
import eu.siacs.conversations.ui.widget.Switch;
|
import eu.siacs.conversations.ui.widget.Switch;
|
||||||
import eu.siacs.conversations.utils.CryptoHelper;
|
import eu.siacs.conversations.utils.CryptoHelper;
|
||||||
import eu.siacs.conversations.utils.ExceptionHelper;
|
import eu.siacs.conversations.utils.ExceptionHelper;
|
||||||
|
import eu.siacs.conversations.xmpp.OnNewKeysAvailable;
|
||||||
import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
|
import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
|
||||||
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;
|
||||||
|
@ -296,6 +297,9 @@ public abstract class XmppActivity extends Activity {
|
||||||
if (this instanceof XmppConnectionService.OnShowErrorToast) {
|
if (this instanceof XmppConnectionService.OnShowErrorToast) {
|
||||||
this.xmppConnectionService.setOnShowErrorToastListener((XmppConnectionService.OnShowErrorToast) this);
|
this.xmppConnectionService.setOnShowErrorToastListener((XmppConnectionService.OnShowErrorToast) this);
|
||||||
}
|
}
|
||||||
|
if (this instanceof OnNewKeysAvailable) {
|
||||||
|
this.xmppConnectionService.setOnNewKeysAvailableListener((OnNewKeysAvailable) this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void unregisterListeners() {
|
protected void unregisterListeners() {
|
||||||
|
@ -317,6 +321,9 @@ public abstract class XmppActivity extends Activity {
|
||||||
if (this instanceof XmppConnectionService.OnShowErrorToast) {
|
if (this instanceof XmppConnectionService.OnShowErrorToast) {
|
||||||
this.xmppConnectionService.removeOnShowErrorToastListener();
|
this.xmppConnectionService.removeOnShowErrorToastListener();
|
||||||
}
|
}
|
||||||
|
if (this instanceof OnNewKeysAvailable) {
|
||||||
|
this.xmppConnectionService.removeOnNewKeysAvailableListener();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -452,7 +459,7 @@ public abstract class XmppActivity extends Activity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void userInputRequried(PendingIntent pi,
|
public void userInputRequried(PendingIntent pi,
|
||||||
Account account) {
|
Account account) {
|
||||||
try {
|
try {
|
||||||
startIntentSenderForResult(pi.getIntentSender(),
|
startIntentSenderForResult(pi.getIntentSender(),
|
||||||
REQUEST_ANNOUNCE_PGP, null, 0, 0, 0);
|
REQUEST_ANNOUNCE_PGP, null, 0, 0, 0);
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
package eu.siacs.conversations.xmpp;
|
||||||
|
|
||||||
|
public interface OnNewKeysAvailable {
|
||||||
|
public void onNewKeysAvailable();
|
||||||
|
}
|
|
@ -0,0 +1,120 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/grey200" >
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_above="@+id/button_bar"
|
||||||
|
android:layout_alignParentTop="true" >
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/own_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"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/own_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/own_keys_details"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:divider="?android:dividerHorizontal"
|
||||||
|
android:showDividers="middle"
|
||||||
|
android:orientation="vertical">
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
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"
|
||||||
|
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">
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/button_bar"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_alignParentLeft="true"
|
||||||
|
android:layout_alignParentRight="true" >
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/cancel_button"
|
||||||
|
style="?android:attr/borderlessButtonStyle"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/cancel"
|
||||||
|
android:textColor="@color/black87" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="1dp"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:layout_marginBottom="7dp"
|
||||||
|
android:layout_marginTop="7dp"
|
||||||
|
android:background="@color/black12" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/save_button"
|
||||||
|
style="?android:attr/borderlessButtonStyle"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:enabled="true"
|
||||||
|
android:textColor="@color/black54"
|
||||||
|
android:text="@string/done"/>
|
||||||
|
</LinearLayout>
|
||||||
|
</RelativeLayout>
|
|
@ -211,6 +211,9 @@
|
||||||
<string name="axolotl_fingerprint">Axolotl fingerprint</string>
|
<string name="axolotl_fingerprint">Axolotl fingerprint</string>
|
||||||
<string name="this_device_axolotl_fingerprint">Own Axolotl fingerprint</string>
|
<string name="this_device_axolotl_fingerprint">Own Axolotl fingerprint</string>
|
||||||
<string name="other_devices">Other devices</string>
|
<string name="other_devices">Other devices</string>
|
||||||
|
<string name="trust_keys">Trust Axolotl Keys</string>
|
||||||
|
<string name="fetching_keys">Fetching keys...</string>
|
||||||
|
<string name="done">Done</string>
|
||||||
<string name="axolotl_devicelist">Other own Axolotl Devices</string>
|
<string name="axolotl_devicelist">Other own Axolotl Devices</string>
|
||||||
<string name="verify">Verify</string>
|
<string name="verify">Verify</string>
|
||||||
<string name="decrypt">Decrypt</string>
|
<string name="decrypt">Decrypt</string>
|
||||||
|
|
Loading…
Reference in New Issue