mirror of
https://github.com/moparisthebest/Conversations
synced 2024-11-28 11:42:15 -05:00
Add purge axolotl key option
Can now long-press a key to permanently purge it.
This commit is contained in:
parent
0ee64124fe
commit
ab2d114bbc
@ -100,7 +100,8 @@ public class AxolotlService {
|
|||||||
public enum Trust {
|
public enum Trust {
|
||||||
UNDECIDED, // 0
|
UNDECIDED, // 0
|
||||||
TRUSTED,
|
TRUSTED,
|
||||||
UNTRUSTED;
|
UNTRUSTED,
|
||||||
|
COMPROMISED;
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
switch(this){
|
switch(this){
|
||||||
@ -514,8 +515,16 @@ public class AxolotlService {
|
|||||||
return fingerprint;
|
return fingerprint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private SQLiteAxolotlStore.Trust getTrust() {
|
||||||
|
return sqLiteAxolotlStore.getFingerprintTrust(fingerprint);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
public byte[] processReceiving(XmppAxolotlMessage.XmppAxolotlMessageHeader incomingHeader) {
|
public byte[] processReceiving(XmppAxolotlMessage.XmppAxolotlMessageHeader incomingHeader) {
|
||||||
byte[] plaintext = null;
|
byte[] plaintext = null;
|
||||||
|
switch (getTrust()) {
|
||||||
|
case UNDECIDED:
|
||||||
|
case TRUSTED:
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
PreKeyWhisperMessage message = new PreKeyWhisperMessage(incomingHeader.getContents());
|
PreKeyWhisperMessage message = new PreKeyWhisperMessage(incomingHeader.getContents());
|
||||||
@ -540,15 +549,30 @@ public class AxolotlService {
|
|||||||
} catch (LegacyMessageException | InvalidMessageException | DuplicateMessageException | NoSessionException e) {
|
} catch (LegacyMessageException | InvalidMessageException | DuplicateMessageException | NoSessionException e) {
|
||||||
Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Error decrypting axolotl header, "+e.getClass().getName()+": " + e.getMessage());
|
Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Error decrypting axolotl header, "+e.getClass().getName()+": " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case COMPROMISED:
|
||||||
|
case UNTRUSTED:
|
||||||
|
default:
|
||||||
|
// ignore
|
||||||
|
break;
|
||||||
|
}
|
||||||
return plaintext;
|
return plaintext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public XmppAxolotlMessage.XmppAxolotlMessageHeader processSending(byte[] outgoingMessage) {
|
@Nullable
|
||||||
|
public XmppAxolotlMessage.XmppAxolotlMessageHeader processSending(@NonNull byte[] outgoingMessage) {
|
||||||
|
SQLiteAxolotlStore.Trust trust = getTrust();
|
||||||
|
if (trust == SQLiteAxolotlStore.Trust.TRUSTED) {
|
||||||
CiphertextMessage ciphertextMessage = cipher.encrypt(outgoingMessage);
|
CiphertextMessage ciphertextMessage = cipher.encrypt(outgoingMessage);
|
||||||
XmppAxolotlMessage.XmppAxolotlMessageHeader header =
|
XmppAxolotlMessage.XmppAxolotlMessageHeader header =
|
||||||
new XmppAxolotlMessage.XmppAxolotlMessageHeader(remoteAddress.getDeviceId(),
|
new XmppAxolotlMessage.XmppAxolotlMessageHeader(remoteAddress.getDeviceId(),
|
||||||
ciphertextMessage.serialize());
|
ciphertextMessage.serialize());
|
||||||
return header;
|
return header;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -742,6 +766,10 @@ public class AxolotlService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void purgeKey(IdentityKey identityKey) {
|
||||||
|
axolotlStore.setFingerprintTrust(identityKey.getFingerprint().replaceAll("\\s",""), SQLiteAxolotlStore.Trust.COMPROMISED);
|
||||||
|
}
|
||||||
|
|
||||||
public void publishOwnDeviceIdIfNeeded() {
|
public void publishOwnDeviceIdIfNeeded() {
|
||||||
IqPacket packet = mXmppConnectionService.getIqGenerator().retrieveDeviceIds(account.getJid().toBareJid());
|
IqPacket packet = mXmppConnectionService.getIqGenerator().retrieveDeviceIds(account.getJid().toBareJid());
|
||||||
mXmppConnectionService.sendIqPacket(account, packet, new OnIqPacketReceived() {
|
mXmppConnectionService.sendIqPacket(account, packet, new OnIqPacketReceived() {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package eu.siacs.conversations.crypto.axolotl;
|
package eu.siacs.conversations.crypto.axolotl;
|
||||||
|
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
|
|
||||||
import java.security.InvalidAlgorithmParameterException;
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
@ -145,9 +146,11 @@ public class XmppAxolotlMessage {
|
|||||||
return headers;
|
return headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addHeader(XmppAxolotlMessageHeader header) {
|
public void addHeader(@Nullable XmppAxolotlMessageHeader header) {
|
||||||
|
if (header != null) {
|
||||||
headers.add(header);
|
headers.add(header);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public byte[] getInnerKey(){
|
public byte[] getInnerKey(){
|
||||||
return innerKey;
|
return innerKey;
|
||||||
|
@ -384,8 +384,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
|
|||||||
}
|
}
|
||||||
for(final IdentityKey identityKey : xmppConnectionService.databaseBackend.loadIdentityKeys(
|
for(final IdentityKey identityKey : xmppConnectionService.databaseBackend.loadIdentityKeys(
|
||||||
contact.getAccount(), contact.getJid().toBareJid().toString())) {
|
contact.getAccount(), contact.getJid().toBareJid().toString())) {
|
||||||
hasKeys = true;
|
hasKeys |= addFingerprintRow(keys, contact.getAccount(), identityKey);
|
||||||
addFingerprintRow(keys, contact.getAccount(), identityKey);
|
|
||||||
}
|
}
|
||||||
if (contact.getPgpKeyId() != 0) {
|
if (contact.getPgpKeyId() != 0) {
|
||||||
hasKeys = true;
|
hasKeys = true;
|
||||||
|
@ -566,8 +566,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
|
|||||||
if(ownKey.equals(identityKey)) {
|
if(ownKey.equals(identityKey)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
hasKeys = true;
|
hasKeys |= addFingerprintRow(keys, mAccount, identityKey);
|
||||||
addFingerprintRow(keys, mAccount, identityKey);
|
|
||||||
}
|
}
|
||||||
if (hasKeys) {
|
if (hasKeys) {
|
||||||
keysCard.setVisibility(View.VISIBLE);
|
keysCard.setVisibility(View.VISIBLE);
|
||||||
|
@ -601,11 +601,11 @@ public abstract class XmppActivity extends Activity {
|
|||||||
builder.create().show();
|
builder.create().show();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void addFingerprintRow(LinearLayout keys, final Account account, IdentityKey identityKey) {
|
protected boolean addFingerprintRow(LinearLayout keys, final Account account, IdentityKey identityKey) {
|
||||||
final String fingerprint = identityKey.getFingerprint().replaceAll("\\s", "");
|
final String fingerprint = identityKey.getFingerprint().replaceAll("\\s", "");
|
||||||
final AxolotlService.SQLiteAxolotlStore.Trust trust = account.getAxolotlService()
|
final AxolotlService.SQLiteAxolotlStore.Trust trust = account.getAxolotlService()
|
||||||
.getFingerprintTrust(fingerprint);
|
.getFingerprintTrust(fingerprint);
|
||||||
addFingerprintRowWithListeners(keys, account, identityKey, trust, true,
|
return addFingerprintRowWithListeners(keys, account, identityKey, trust, true,
|
||||||
new CompoundButton.OnCheckedChangeListener() {
|
new CompoundButton.OnCheckedChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||||
@ -633,13 +633,16 @@ public abstract class XmppActivity extends Activity {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void addFingerprintRowWithListeners(LinearLayout keys, final Account account,
|
protected boolean addFingerprintRowWithListeners(LinearLayout keys, final Account account,
|
||||||
IdentityKey identityKey,
|
final IdentityKey identityKey,
|
||||||
AxolotlService.SQLiteAxolotlStore.Trust trust,
|
AxolotlService.SQLiteAxolotlStore.Trust trust,
|
||||||
boolean showTag,
|
boolean showTag,
|
||||||
CompoundButton.OnCheckedChangeListener
|
CompoundButton.OnCheckedChangeListener
|
||||||
onCheckedChangeListener,
|
onCheckedChangeListener,
|
||||||
View.OnClickListener onClickListener) {
|
View.OnClickListener onClickListener) {
|
||||||
|
if (trust == AxolotlService.SQLiteAxolotlStore.Trust.COMPROMISED) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
View view = getLayoutInflater().inflate(R.layout.contact_key, keys, false);
|
View view = getLayoutInflater().inflate(R.layout.contact_key, keys, false);
|
||||||
TextView key = (TextView) view.findViewById(R.id.key);
|
TextView key = (TextView) view.findViewById(R.id.key);
|
||||||
TextView keyType = (TextView) view.findViewById(R.id.key_type);
|
TextView keyType = (TextView) view.findViewById(R.id.key_type);
|
||||||
@ -647,6 +650,13 @@ public abstract class XmppActivity extends Activity {
|
|||||||
trustToggle.setVisibility(View.VISIBLE);
|
trustToggle.setVisibility(View.VISIBLE);
|
||||||
trustToggle.setOnCheckedChangeListener(onCheckedChangeListener);
|
trustToggle.setOnCheckedChangeListener(onCheckedChangeListener);
|
||||||
trustToggle.setOnClickListener(onClickListener);
|
trustToggle.setOnClickListener(onClickListener);
|
||||||
|
view.setOnLongClickListener(new View.OnLongClickListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onLongClick(View v) {
|
||||||
|
showPurgeKeyDialog(account, identityKey);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
switch (trust) {
|
switch (trust) {
|
||||||
case UNTRUSTED:
|
case UNTRUSTED:
|
||||||
@ -668,7 +678,26 @@ public abstract class XmppActivity extends Activity {
|
|||||||
|
|
||||||
key.setText(CryptoHelper.prettifyFingerprint(identityKey.getFingerprint()));
|
key.setText(CryptoHelper.prettifyFingerprint(identityKey.getFingerprint()));
|
||||||
keys.addView(view);
|
keys.addView(view);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showPurgeKeyDialog(final Account account, final IdentityKey identityKey) {
|
||||||
|
Builder builder = new Builder(this);
|
||||||
|
builder.setTitle(getString(R.string.purge_key));
|
||||||
|
builder.setIconAttribute(android.R.attr.alertDialogIcon);
|
||||||
|
builder.setMessage(getString(R.string.purge_key_desc_part1)
|
||||||
|
+ "\n\n" + CryptoHelper.prettifyFingerprint(identityKey.getFingerprint())
|
||||||
|
+ "\n\n" + getString(R.string.purge_key_desc_part2));
|
||||||
|
builder.setNegativeButton(getString(R.string.cancel), null);
|
||||||
|
builder.setPositiveButton(getString(R.string.accept),
|
||||||
|
new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
account.getAxolotlService().purgeKey(identityKey);
|
||||||
|
refreshUi();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
builder.create().show();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void selectPresence(final Conversation conversation,
|
public void selectPresence(final Conversation conversation,
|
||||||
|
@ -393,6 +393,9 @@
|
|||||||
<string name="wipe_axolotl_pep">Wipe other devices from PEP</string>
|
<string name="wipe_axolotl_pep">Wipe other devices from PEP</string>
|
||||||
<string name="clear_other_devices">Clear devices</string>
|
<string name="clear_other_devices">Clear devices</string>
|
||||||
<string name="clear_other_devices_desc">Are you sure you want to clear all other devices from the axolotl announcement? The next time your devices connect, they will reannounce themselves, but they might not receive messages sent in the meantime.</string>
|
<string name="clear_other_devices_desc">Are you sure you want to clear all other devices from the axolotl announcement? The next time your devices connect, they will reannounce themselves, but they might not receive messages sent in the meantime.</string>
|
||||||
|
<string name="purge_key">Purge key</string>
|
||||||
|
<string name="purge_key_desc_part1">Are you sure you want to purge this key?</string>
|
||||||
|
<string name="purge_key_desc_part2">It will irreversibly be considered compromised, and you can never build a session with it again.</string>
|
||||||
<string name="fetching_history_from_server">Fetching history from server</string>
|
<string name="fetching_history_from_server">Fetching history from server</string>
|
||||||
<string name="no_more_history_on_server">No more history on server</string>
|
<string name="no_more_history_on_server">No more history on server</string>
|
||||||
<string name="updating">Updating…</string>
|
<string name="updating">Updating…</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user