parse omemo fingerprints from uris
This commit is contained in:
parent
3f3b360eee
commit
7e2e42cb11
|
@ -98,6 +98,10 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
|
|||
return false;
|
||||
}
|
||||
|
||||
public void preVerifyFingerprint(Contact contact, String fingerprint) {
|
||||
axolotlStore.preVerifyFingerprint(contact.getAccount(), contact.getJid().toBareJid().toPreppedString(), fingerprint);
|
||||
}
|
||||
|
||||
private static class AxolotlAddressMap<T> {
|
||||
protected Map<String, Map<Integer, T>> map;
|
||||
protected final Object MAP_LOCK = new Object();
|
||||
|
@ -200,7 +204,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
|
|||
public void put(AxolotlAddress address, XmppAxolotlSession value) {
|
||||
super.put(address, value);
|
||||
value.setNotFresh();
|
||||
xmppConnectionService.syncRosterToDisk(account);
|
||||
xmppConnectionService.syncRosterToDisk(account); //TODO why?
|
||||
}
|
||||
|
||||
public void put(XmppAxolotlSession session) {
|
||||
|
@ -417,7 +421,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
|
|||
}
|
||||
|
||||
public void purgeKey(final String fingerprint) {
|
||||
axolotlStore.setFingerprintTrust(fingerprint.replaceAll("\\s", ""), FingerprintStatus.createCompromised());
|
||||
axolotlStore.setFingerprintStatus(fingerprint.replaceAll("\\s", ""), FingerprintStatus.createCompromised());
|
||||
}
|
||||
|
||||
public void publishOwnDeviceIdIfNeeded() {
|
||||
|
@ -690,7 +694,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
|
|||
}
|
||||
|
||||
public void setFingerprintTrust(String fingerprint, FingerprintStatus status) {
|
||||
axolotlStore.setFingerprintTrust(fingerprint, status);
|
||||
axolotlStore.setFingerprintStatus(fingerprint, status);
|
||||
}
|
||||
|
||||
private void verifySessionWithPEP(final XmppAxolotlSession session) {
|
||||
|
@ -749,14 +753,15 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
|
|||
|
||||
private void finishBuildingSessionsFromPEP(final AxolotlAddress address) {
|
||||
AxolotlAddress ownAddress = new AxolotlAddress(account.getJid().toBareJid().toPreppedString(), 0);
|
||||
if (!fetchStatusMap.getAll(ownAddress).containsValue(FetchStatus.PENDING)
|
||||
&& !fetchStatusMap.getAll(address).containsValue(FetchStatus.PENDING)) {
|
||||
Map<Integer, FetchStatus> own = fetchStatusMap.getAll(ownAddress);
|
||||
Map<Integer, FetchStatus> remote = fetchStatusMap.getAll(address);
|
||||
if (!own.containsValue(FetchStatus.PENDING) && !remote.containsValue(FetchStatus.PENDING)) {
|
||||
FetchStatus report = null;
|
||||
if (fetchStatusMap.getAll(ownAddress).containsValue(FetchStatus.SUCCESS_VERIFIED)
|
||||
| fetchStatusMap.getAll(address).containsValue(FetchStatus.SUCCESS_VERIFIED)) {
|
||||
if (own.containsValue(FetchStatus.SUCCESS) || remote.containsValue(FetchStatus.SUCCESS)) {
|
||||
report = FetchStatus.SUCCESS;
|
||||
} else if (own.containsValue(FetchStatus.SUCCESS_VERIFIED) || remote.containsValue(FetchStatus.SUCCESS_VERIFIED)) {
|
||||
report = FetchStatus.SUCCESS_VERIFIED;
|
||||
} else if (fetchStatusMap.getAll(ownAddress).containsValue(FetchStatus.ERROR)
|
||||
|| fetchStatusMap.getAll(address).containsValue(FetchStatus.ERROR)) {
|
||||
} else if (own.containsValue(FetchStatus.ERROR) || remote.containsValue(FetchStatus.ERROR)) {
|
||||
report = FetchStatus.ERROR;
|
||||
}
|
||||
mXmppConnectionService.keyStatusUpdated(report);
|
||||
|
@ -812,7 +817,9 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
|
|||
if (Config.X509_VERIFICATION) {
|
||||
verifySessionWithPEP(session);
|
||||
} else {
|
||||
fetchStatusMap.put(address, FetchStatus.SUCCESS);
|
||||
FingerprintStatus status = getFingerprintTrust(bundle.getIdentityKey().getFingerprint().replaceAll("\\s",""));
|
||||
boolean verified = status != null && status.isVerified();
|
||||
fetchStatusMap.put(address, verified ? FetchStatus.SUCCESS_VERIFIED : FetchStatus.SUCCESS);
|
||||
finishBuildingSessionsFromPEP(address);
|
||||
}
|
||||
} catch (UntrustedIdentityException | InvalidKeyException e) {
|
||||
|
|
|
@ -114,6 +114,20 @@ public class FingerprintStatus {
|
|||
return status;
|
||||
}
|
||||
|
||||
public FingerprintStatus toVerified() {
|
||||
FingerprintStatus status = new FingerprintStatus();
|
||||
status.active = active;
|
||||
status.trust = Trust.VERIFIED;
|
||||
return status;
|
||||
}
|
||||
|
||||
public static FingerprintStatus createInactiveVerified() {
|
||||
final FingerprintStatus status = new FingerprintStatus();
|
||||
status.trust = Trust.VERIFIED;
|
||||
status.active = false;
|
||||
return status;
|
||||
}
|
||||
|
||||
public enum Trust {
|
||||
COMPROMISED,
|
||||
UNDECIDED,
|
||||
|
|
|
@ -187,7 +187,15 @@ public class SQLiteAxolotlStore implements AxolotlStore {
|
|||
@Override
|
||||
public void saveIdentity(String name, IdentityKey identityKey) {
|
||||
if (!mXmppConnectionService.databaseBackend.loadIdentityKeys(account, name).contains(identityKey)) {
|
||||
mXmppConnectionService.databaseBackend.storeIdentityKey(account, name, identityKey);
|
||||
String fingerprint = identityKey.getFingerprint().replaceAll("\\s", "");
|
||||
FingerprintStatus status = getFingerprintStatus(fingerprint);
|
||||
if (status == null) {
|
||||
status = FingerprintStatus.createActiveUndecided(); //default for new keys
|
||||
} else {
|
||||
status = status.toActive();
|
||||
}
|
||||
mXmppConnectionService.databaseBackend.storeIdentityKey(account, name, identityKey, status);
|
||||
trustCache.remove(fingerprint);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,7 +222,7 @@ public class SQLiteAxolotlStore implements AxolotlStore {
|
|||
return (fingerprint == null)? null : trustCache.get(fingerprint);
|
||||
}
|
||||
|
||||
public void setFingerprintTrust(String fingerprint, FingerprintStatus status) {
|
||||
public void setFingerprintStatus(String fingerprint, FingerprintStatus status) {
|
||||
mXmppConnectionService.databaseBackend.setIdentityKeyTrust(account, fingerprint, status);
|
||||
trustCache.remove(fingerprint);
|
||||
}
|
||||
|
@ -430,4 +438,8 @@ public class SQLiteAxolotlStore implements AxolotlStore {
|
|||
public void removeSignedPreKey(int signedPreKeyId) {
|
||||
mXmppConnectionService.databaseBackend.deleteSignedPreKey(account, signedPreKeyId);
|
||||
}
|
||||
|
||||
public void preVerifyFingerprint(Account account, String name, String fingerprint) {
|
||||
mXmppConnectionService.databaseBackend.storePreVerification(account,name,fingerprint,FingerprintStatus.createInactiveVerified());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ public class XmppAxolotlSession {
|
|||
}
|
||||
|
||||
protected void setTrust(FingerprintStatus status) {
|
||||
sqLiteAxolotlStore.setFingerprintTrust(getFingerprint(), status);
|
||||
sqLiteAxolotlStore.setFingerprintStatus(getFingerprint(), status);
|
||||
}
|
||||
|
||||
protected FingerprintStatus getTrust() {
|
||||
|
|
|
@ -1106,7 +1106,12 @@ public class DatabaseBackend extends SQLiteOpenHelper {
|
|||
continue;
|
||||
}
|
||||
try {
|
||||
identityKeys.add(new IdentityKey(Base64.decode(cursor.getString(cursor.getColumnIndex(SQLiteAxolotlStore.KEY)), Base64.DEFAULT), 0));
|
||||
String key = cursor.getString(cursor.getColumnIndex(SQLiteAxolotlStore.KEY));
|
||||
if (key != null) {
|
||||
identityKeys.add(new IdentityKey(Base64.decode(key, Base64.DEFAULT), 0));
|
||||
} else {
|
||||
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Missing key (possibly preverified) in database for account" + account.getJid().toBareJid() + ", address: " + name);
|
||||
}
|
||||
} catch (InvalidKeyException e) {
|
||||
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Encountered invalid IdentityKey in database for account" + account.getJid().toBareJid() + ", address: " + name);
|
||||
}
|
||||
|
@ -1134,10 +1139,6 @@ public class DatabaseBackend extends SQLiteOpenHelper {
|
|||
);
|
||||
}
|
||||
|
||||
private void storeIdentityKey(Account account, String name, boolean own, String fingerprint, String base64Serialized) {
|
||||
storeIdentityKey(account, name, own, fingerprint, base64Serialized, FingerprintStatus.createActiveUndecided());
|
||||
}
|
||||
|
||||
private void storeIdentityKey(Account account, String name, boolean own, String fingerprint, String base64Serialized, FingerprintStatus status) {
|
||||
SQLiteDatabase db = this.getWritableDatabase();
|
||||
ContentValues values = new ContentValues();
|
||||
|
@ -1147,6 +1148,22 @@ public class DatabaseBackend extends SQLiteOpenHelper {
|
|||
values.put(SQLiteAxolotlStore.FINGERPRINT, fingerprint);
|
||||
values.put(SQLiteAxolotlStore.KEY, base64Serialized);
|
||||
values.putAll(status.toContentValues());
|
||||
String where = SQLiteAxolotlStore.ACCOUNT+"=? AND "+SQLiteAxolotlStore.NAME+"=? AND "+SQLiteAxolotlStore.FINGERPRINT+" =?";
|
||||
String[] whereArgs = {account.getUuid(),name,fingerprint};
|
||||
int rows = db.update(SQLiteAxolotlStore.IDENTITIES_TABLENAME,values,where,whereArgs);
|
||||
if (rows == 0) {
|
||||
db.insert(SQLiteAxolotlStore.IDENTITIES_TABLENAME, null, values);
|
||||
}
|
||||
}
|
||||
|
||||
public void storePreVerification(Account account, String name, String fingerprint, FingerprintStatus status) {
|
||||
SQLiteDatabase db = this.getWritableDatabase();
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(SQLiteAxolotlStore.ACCOUNT, account.getUuid());
|
||||
values.put(SQLiteAxolotlStore.NAME, name);
|
||||
values.put(SQLiteAxolotlStore.OWN, 0);
|
||||
values.put(SQLiteAxolotlStore.FINGERPRINT, fingerprint);
|
||||
values.putAll(status.toContentValues());
|
||||
db.insert(SQLiteAxolotlStore.IDENTITIES_TABLENAME, null, values);
|
||||
}
|
||||
|
||||
|
@ -1227,8 +1244,8 @@ public class DatabaseBackend extends SQLiteOpenHelper {
|
|||
}
|
||||
}
|
||||
|
||||
public void storeIdentityKey(Account account, String name, IdentityKey identityKey) {
|
||||
storeIdentityKey(account, name, false, identityKey.getFingerprint().replaceAll("\\s", ""), Base64.encodeToString(identityKey.serialize(), Base64.DEFAULT));
|
||||
public void storeIdentityKey(Account account, String name, IdentityKey identityKey, FingerprintStatus status) {
|
||||
storeIdentityKey(account, name, false, identityKey.getFingerprint().replaceAll("\\s", ""), Base64.encodeToString(identityKey.serialize(), Base64.DEFAULT), status);
|
||||
}
|
||||
|
||||
public void storeOwnIdentityKeyPair(Account account, IdentityKeyPair identityKeyPair) {
|
||||
|
|
|
@ -65,6 +65,7 @@ import eu.siacs.conversations.R;
|
|||
import eu.siacs.conversations.crypto.PgpDecryptionService;
|
||||
import eu.siacs.conversations.crypto.PgpEngine;
|
||||
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
|
||||
import eu.siacs.conversations.crypto.axolotl.FingerprintStatus;
|
||||
import eu.siacs.conversations.crypto.axolotl.XmppAxolotlMessage;
|
||||
import eu.siacs.conversations.entities.Account;
|
||||
import eu.siacs.conversations.entities.Blockable;
|
||||
|
@ -102,6 +103,7 @@ import eu.siacs.conversations.utils.PhoneHelper;
|
|||
import eu.siacs.conversations.utils.ReplacingSerialSingleThreadExecutor;
|
||||
import eu.siacs.conversations.utils.SerialSingleThreadExecutor;
|
||||
import eu.siacs.conversations.utils.Xmlns;
|
||||
import eu.siacs.conversations.utils.XmppUri;
|
||||
import eu.siacs.conversations.xml.Element;
|
||||
import eu.siacs.conversations.xmpp.OnBindListener;
|
||||
import eu.siacs.conversations.xmpp.OnContactStatusChanged;
|
||||
|
@ -3608,6 +3610,29 @@ public class XmppConnectionService extends Service {
|
|||
});
|
||||
}
|
||||
|
||||
public void verifyFingerprints(Contact contact, List<XmppUri.Fingerprint> fingerprints) {
|
||||
boolean needsRosterWrite = false;
|
||||
final AxolotlService axolotlService = contact.getAccount().getAxolotlService();
|
||||
for(XmppUri.Fingerprint fp : fingerprints) {
|
||||
if (fp.type == XmppUri.FingerprintType.OTR) {
|
||||
needsRosterWrite |= contact.addOtrFingerprint(fp.fingerprint);
|
||||
} else if (fp.type == XmppUri.FingerprintType.OMEMO) {
|
||||
String fingerprint = "05"+fp.fingerprint.replaceAll("\\s","");
|
||||
FingerprintStatus fingerprintStatus = axolotlService.getFingerprintTrust(fingerprint);
|
||||
if (fingerprintStatus != null) {
|
||||
if (!fingerprintStatus.isVerified()) {
|
||||
axolotlService.setFingerprintTrust(fingerprint,fingerprintStatus.toVerified());
|
||||
}
|
||||
} else {
|
||||
axolotlService.preVerifyFingerprint(contact,fingerprint);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (needsRosterWrite) {
|
||||
syncRosterToDisk(contact.getAccount());
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnMamPreferencesFetched {
|
||||
void onPreferencesFetched(Element prefs);
|
||||
void onPreferencesFetchFailed();
|
||||
|
|
|
@ -397,11 +397,11 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
|
|||
}
|
||||
|
||||
@SuppressLint("InflateParams")
|
||||
protected void showCreateContactDialog(final String prefilledJid, final String fingerprint) {
|
||||
protected void showCreateContactDialog(final String prefilledJid, final Invite invite) {
|
||||
EnterJidDialog dialog = new EnterJidDialog(
|
||||
this, mKnownHosts, mActivatedAccounts,
|
||||
getString(R.string.create_contact), getString(R.string.create),
|
||||
prefilledJid, null, fingerprint == null
|
||||
prefilledJid, null, !invite.hasFingerprints()
|
||||
);
|
||||
|
||||
dialog.setOnEnterJidDialogPositiveListener(new EnterJidDialog.OnEnterJidDialogPositiveListener() {
|
||||
|
@ -420,7 +420,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
|
|||
if (contact.showInRoster()) {
|
||||
throw new EnterJidDialog.JidError(getString(R.string.contact_already_exists));
|
||||
} else {
|
||||
contact.addOtrFingerprint(fingerprint);
|
||||
//contact.addOtrFingerprint(fingerprint);
|
||||
xmppConnectionService.createContact(contact);
|
||||
switchToConversation(contact);
|
||||
return true;
|
||||
|
@ -842,6 +842,10 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
|
|||
}
|
||||
|
||||
private boolean handleJid(Invite invite) {
|
||||
Log.d(Config.LOGTAG,"handling invite for "+invite.getJid());
|
||||
for(XmppUri.Fingerprint fp : invite.getFingerprints()) {
|
||||
Log.d(Config.LOGTAG,fp.toString());
|
||||
}
|
||||
List<Contact> contacts = xmppConnectionService.findContacts(invite.getJid());
|
||||
if (invite.isMuc()) {
|
||||
Conversation muc = xmppConnectionService.findFirstMuc(invite.getJid());
|
||||
|
@ -853,16 +857,19 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
|
|||
return false;
|
||||
}
|
||||
} else if (contacts.size() == 0) {
|
||||
showCreateContactDialog(invite.getJid().toString(), invite.getFingerprint());
|
||||
showCreateContactDialog(invite.getJid().toString(), invite);
|
||||
return false;
|
||||
} else if (contacts.size() == 1) {
|
||||
Contact contact = contacts.get(0);
|
||||
if (invite.getFingerprint() != null) {
|
||||
if (invite.hasFingerprints()) {
|
||||
xmppConnectionService.verifyFingerprints(contact,invite.getFingerprints());
|
||||
}
|
||||
/*if (invite.getFingerprint() != null) {
|
||||
if (contact.addOtrFingerprint(invite.getFingerprint())) {
|
||||
Log.d(Config.LOGTAG, "added new fingerprint");
|
||||
xmppConnectionService.syncRosterToDisk(contact.getAccount());
|
||||
}
|
||||
}
|
||||
}*/
|
||||
switchToConversation(contact);
|
||||
return true;
|
||||
} else {
|
||||
|
|
|
@ -18,6 +18,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import eu.siacs.conversations.Config;
|
||||
import eu.siacs.conversations.OmemoActivity;
|
||||
import eu.siacs.conversations.R;
|
||||
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
|
||||
|
@ -245,7 +246,9 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
|
|||
Toast.makeText(TrustKeysActivity.this,R.string.error_fetching_omemo_key,Toast.LENGTH_SHORT).show();
|
||||
break;
|
||||
case SUCCESS_VERIFIED:
|
||||
Toast.makeText(TrustKeysActivity.this,R.string.verified_omemo_key_with_certificate,Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(TrustKeysActivity.this,
|
||||
Config.X509_VERIFICATION ? R.string.verified_omemo_key_with_certificate : R.string.all_omemo_keys_have_been_verified,
|
||||
Toast.LENGTH_LONG).show();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -173,11 +173,10 @@ public class VerifyOTRActivity extends XmppActivity implements XmppConnectionSer
|
|||
|
||||
protected boolean verifyWithUri(XmppUri uri) {
|
||||
Contact contact = mConversation.getContact();
|
||||
if (this.mConversation.getContact().getJid().equals(uri.getJid()) && uri.getFingerprint() != null) {
|
||||
contact.addOtrFingerprint(uri.getFingerprint());
|
||||
if (this.mConversation.getContact().getJid().equals(uri.getJid()) && uri.hasFingerprints()) {
|
||||
xmppConnectionService.verifyFingerprints(contact,uri.getFingerprints());
|
||||
Toast.makeText(this,R.string.verified,Toast.LENGTH_SHORT).show();
|
||||
updateView();
|
||||
xmppConnectionService.syncRosterToDisk(contact.getAccount());
|
||||
return true;
|
||||
} else {
|
||||
Toast.makeText(this,R.string.could_not_verify_fingerprint,Toast.LENGTH_SHORT).show();
|
||||
|
|
|
@ -4,7 +4,9 @@ import android.net.Uri;
|
|||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
|
||||
import eu.siacs.conversations.xmpp.jid.Jid;
|
||||
|
@ -13,7 +15,9 @@ public class XmppUri {
|
|||
|
||||
protected String jid;
|
||||
protected boolean muc;
|
||||
protected String fingerprint;
|
||||
protected List<Fingerprint> fingerprints = new ArrayList<>();
|
||||
|
||||
private static final String OMEMO_URI_PARAM = "omemo-sid-";
|
||||
|
||||
public XmppUri(String uri) {
|
||||
try {
|
||||
|
@ -56,7 +60,7 @@ public class XmppUri {
|
|||
} else {
|
||||
jid = uri.getSchemeSpecificPart().split("\\?")[0];
|
||||
}
|
||||
fingerprint = parseFingerprint(uri.getQuery());
|
||||
this.fingerprints = parseFingerprints(uri.getQuery());
|
||||
} else if ("imto".equalsIgnoreCase(scheme)) {
|
||||
// sample: imto://xmpp/foo@bar.com
|
||||
try {
|
||||
|
@ -73,18 +77,28 @@ public class XmppUri {
|
|||
}
|
||||
}
|
||||
|
||||
protected String parseFingerprint(String query) {
|
||||
if (query == null) {
|
||||
return null;
|
||||
} else {
|
||||
final String NEEDLE = "otr-fingerprint=";
|
||||
int index = query.indexOf(NEEDLE);
|
||||
if (index >= 0 && query.length() >= (NEEDLE.length() + index + 40)) {
|
||||
return query.substring(index + NEEDLE.length(), index + NEEDLE.length() + 40);
|
||||
} else {
|
||||
return null;
|
||||
protected List<Fingerprint> parseFingerprints(String query) {
|
||||
List<Fingerprint> fingerprints = new ArrayList<>();
|
||||
String[] pairs = query == null ? new String[0] : query.split(";");
|
||||
for(String pair : pairs) {
|
||||
String[] parts = pair.split("=",2);
|
||||
if (parts.length == 2) {
|
||||
String key = parts[0].toLowerCase(Locale.US);
|
||||
String value = parts[1];
|
||||
if ("otr-fingerprint".equals(key)) {
|
||||
fingerprints.add(new Fingerprint(FingerprintType.OTR,value));
|
||||
}
|
||||
if (key.startsWith(OMEMO_URI_PARAM)) {
|
||||
try {
|
||||
int id = Integer.parseInt(key.substring(OMEMO_URI_PARAM.length()));
|
||||
fingerprints.add(new Fingerprint(FingerprintType.OMEMO,value,id));
|
||||
} catch (Exception e) {
|
||||
//ignoring invalid device id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return fingerprints;
|
||||
}
|
||||
|
||||
public Jid getJid() {
|
||||
|
@ -95,7 +109,36 @@ public class XmppUri {
|
|||
}
|
||||
}
|
||||
|
||||
public String getFingerprint() {
|
||||
return this.fingerprint;
|
||||
public List<Fingerprint> getFingerprints() {
|
||||
return this.fingerprints;
|
||||
}
|
||||
|
||||
public boolean hasFingerprints() {
|
||||
return fingerprints.size() > 0;
|
||||
}
|
||||
public enum FingerprintType {
|
||||
OMEMO,
|
||||
OTR
|
||||
}
|
||||
|
||||
public static class Fingerprint {
|
||||
public final FingerprintType type;
|
||||
public final String fingerprint;
|
||||
public final int deviceId;
|
||||
|
||||
public Fingerprint(FingerprintType type, String fingerprint) {
|
||||
this(type, fingerprint, 0);
|
||||
}
|
||||
|
||||
public Fingerprint(FingerprintType type, String fingerprint, int deviceId) {
|
||||
this.type = type;
|
||||
this.fingerprint = fingerprint;
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return type.toString()+": "+fingerprint+(deviceId != 0 ? " "+String.valueOf(deviceId) : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -702,4 +702,5 @@
|
|||
<string name="error_unable_to_create_temporary_file">Unable to create temporary file</string>
|
||||
<string name="this_device_has_been_verified">This device has been verified</string>
|
||||
<string name="copy_fingerprint">Copy fingerprint</string>
|
||||
<string name="all_omemo_keys_have_been_verified">All OMEMO keys have been verified</string>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in New Issue