From 601e233d47acca056c05eca8205ffc2bf10eebc1 Mon Sep 17 00:00:00 2001 From: Moxie Marlinspike Date: Sun, 9 Nov 2014 20:35:08 -0800 Subject: [PATCH] Add account management interface to libtextsecure api --- .../api/TextSecureAccountManager.java | 76 ++++++ .../api/TextSecureMessageReceiver.java | 9 +- .../api/TextSecureMessageSender.java | 17 +- .../textsecure/push/PushAddress.java | 8 - .../textsecure/push/PushServiceSocket.java | 5 +- .../ApplicationPreferencesActivity.java | 13 +- .../securesms/GroupCreateActivity.java | 8 +- .../RegistrationProgressActivity.java | 16 +- .../securesms/contacts/ContactAccessor.java | 4 +- .../database}/NotInDirectoryException.java | 2 +- .../database/TextSecureDirectory.java | 12 +- .../securesms/jobs/AttachmentDownloadJob.java | 5 +- .../securesms/jobs/AvatarDownloadJob.java | 12 +- .../securesms/jobs/CleanPreKeysJob.java | 135 ++++++++++ .../securesms/jobs/CreateSignedPreKeyJob.java | 16 +- .../securesms/jobs/DeliveryReceiptJob.java | 23 +- .../securesms/jobs/GcmRefreshJob.java | 12 +- .../securesms/jobs/PushGroupSendJob.java | 4 +- .../securesms/jobs/PushMediaSendJob.java | 4 +- .../securesms/jobs/PushReceiveJob.java | 8 +- .../securesms/jobs/PushSendJob.java | 6 +- .../securesms/jobs/PushTextSendJob.java | 4 +- .../securesms/jobs/RefreshPreKeysJob.java | 85 +++++++ .../push/PushServiceSocketFactory.java | 22 -- ...va => TextSecureCommunicationFactory.java} | 29 ++- .../TextSecureMessageReceiverFactory.java | 21 -- .../service/DirectoryRefreshService.java | 1 - .../service/GcmRegistrationService.java | 83 ------- .../securesms/service/PreKeyService.java | 230 ------------------ .../service/RegistrationService.java | 31 +-- .../securesms/sms/MessageSender.java | 31 +-- .../securesms/util/DirectoryHelper.java | 24 +- 32 files changed, 464 insertions(+), 492 deletions(-) create mode 100644 library/src/org/whispersystems/textsecure/api/TextSecureAccountManager.java rename {library/src/org/whispersystems/textsecure/directory => src/org/thoughtcrime/securesms/database}/NotInDirectoryException.java (55%) rename library/src/org/whispersystems/textsecure/directory/Directory.java => src/org/thoughtcrime/securesms/database/TextSecureDirectory.java (96%) create mode 100644 src/org/thoughtcrime/securesms/jobs/CleanPreKeysJob.java create mode 100644 src/org/thoughtcrime/securesms/jobs/RefreshPreKeysJob.java delete mode 100644 src/org/thoughtcrime/securesms/push/PushServiceSocketFactory.java rename src/org/thoughtcrime/securesms/push/{TextSecureMessageSenderFactory.java => TextSecureCommunicationFactory.java} (52%) delete mode 100644 src/org/thoughtcrime/securesms/push/TextSecureMessageReceiverFactory.java delete mode 100644 src/org/thoughtcrime/securesms/service/GcmRegistrationService.java delete mode 100644 src/org/thoughtcrime/securesms/service/PreKeyService.java diff --git a/library/src/org/whispersystems/textsecure/api/TextSecureAccountManager.java b/library/src/org/whispersystems/textsecure/api/TextSecureAccountManager.java new file mode 100644 index 0000000000..d065f778a0 --- /dev/null +++ b/library/src/org/whispersystems/textsecure/api/TextSecureAccountManager.java @@ -0,0 +1,76 @@ +package org.whispersystems.textsecure.api; + +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.state.PreKeyRecord; +import org.whispersystems.libaxolotl.state.SignedPreKeyRecord; +import org.whispersystems.libaxolotl.util.guava.Optional; +import org.whispersystems.textsecure.push.ContactTokenDetails; +import org.whispersystems.textsecure.push.PushServiceSocket; +import org.whispersystems.textsecure.push.SignedPreKeyEntity; + +import java.io.IOException; +import java.util.List; +import java.util.Set; + +public class TextSecureAccountManager { + + private final PushServiceSocket pushServiceSocket; + + public TextSecureAccountManager(String url, PushServiceSocket.TrustStore trustStore, + String user, String password) + { + this.pushServiceSocket = new PushServiceSocket(url, trustStore, user, password); + } + + public void setGcmId(Optional gcmRegistrationId) throws IOException { + if (gcmRegistrationId.isPresent()) { + this.pushServiceSocket.registerGcmId(gcmRegistrationId.get()); + } else { + this.pushServiceSocket.unregisterGcmId(); + } + } + + public void requestSmsVerificationCode() throws IOException { + this.pushServiceSocket.createAccount(false); + } + + public void requestVoiceVerificationCode() throws IOException { + this.pushServiceSocket.createAccount(true); + } + + public void verifyAccount(String verificationCode, String signalingKey, + boolean supportsSms, int axolotlRegistrationId) + throws IOException + { + this.pushServiceSocket.verifyAccount(verificationCode, signalingKey, + supportsSms, axolotlRegistrationId); + } + + public void setPreKeys(IdentityKey identityKey, PreKeyRecord lastResortKey, + SignedPreKeyRecord signedPreKey, List oneTimePreKeys) + throws IOException + { + this.pushServiceSocket.registerPreKeys(identityKey, lastResortKey, signedPreKey, oneTimePreKeys); + } + + public int getPreKeysCount() throws IOException { + return this.pushServiceSocket.getAvailablePreKeys(); + } + + public void setSignedPreKey(SignedPreKeyRecord signedPreKey) throws IOException { + this.pushServiceSocket.setCurrentSignedPreKey(signedPreKey); + } + + public SignedPreKeyEntity getSignedPreKey() throws IOException { + return this.pushServiceSocket.getCurrentSignedPreKey(); + } + + public Optional getContact(String contactToken) throws IOException { + return Optional.fromNullable(this.pushServiceSocket.getContactTokenDetails(contactToken)); + } + + public List getContacts(Set contactTokens) { + return this.pushServiceSocket.retrieveDirectory(contactTokens); + } + +} diff --git a/library/src/org/whispersystems/textsecure/api/TextSecureMessageReceiver.java b/library/src/org/whispersystems/textsecure/api/TextSecureMessageReceiver.java index 07f52f195f..efc79d19eb 100644 --- a/library/src/org/whispersystems/textsecure/api/TextSecureMessageReceiver.java +++ b/library/src/org/whispersystems/textsecure/api/TextSecureMessageReceiver.java @@ -1,11 +1,9 @@ package org.whispersystems.textsecure.api; -import android.content.Context; - import org.whispersystems.libaxolotl.InvalidMessageException; import org.whispersystems.libaxolotl.state.AxolotlStore; -import org.whispersystems.textsecure.api.messages.TextSecureAttachmentPointer; import org.whispersystems.textsecure.api.crypto.AttachmentCipherInputStream; +import org.whispersystems.textsecure.api.messages.TextSecureAttachmentPointer; import org.whispersystems.textsecure.push.PushServiceSocket; import java.io.File; @@ -18,15 +16,14 @@ public class TextSecureMessageReceiver { private final AxolotlStore axolotlStore; private final PushServiceSocket socket; - - public TextSecureMessageReceiver(Context context, String signalingKey, String url, + public TextSecureMessageReceiver(String signalingKey, String url, PushServiceSocket.TrustStore trustStore, String user, String password, AxolotlStore axolotlStore) { this.axolotlStore = axolotlStore; this.signalingKey = signalingKey; - this.socket = new PushServiceSocket(context, url, trustStore, user, password); + this.socket = new PushServiceSocket(url, trustStore, user, password); } public InputStream retrieveAttachment(TextSecureAttachmentPointer pointer, File destination) diff --git a/library/src/org/whispersystems/textsecure/api/TextSecureMessageSender.java b/library/src/org/whispersystems/textsecure/api/TextSecureMessageSender.java index e892ddbacc..fb2bf02d29 100644 --- a/library/src/org/whispersystems/textsecure/api/TextSecureMessageSender.java +++ b/library/src/org/whispersystems/textsecure/api/TextSecureMessageSender.java @@ -1,6 +1,5 @@ package org.whispersystems.textsecure.api; -import android.content.Context; import android.util.Log; import com.google.protobuf.ByteString; @@ -11,12 +10,12 @@ import org.whispersystems.libaxolotl.protocol.CiphertextMessage; import org.whispersystems.libaxolotl.state.AxolotlStore; import org.whispersystems.libaxolotl.state.PreKeyBundle; import org.whispersystems.libaxolotl.util.guava.Optional; +import org.whispersystems.textsecure.api.crypto.TextSecureCipher; +import org.whispersystems.textsecure.api.crypto.UntrustedIdentityException; import org.whispersystems.textsecure.api.messages.TextSecureAttachment; import org.whispersystems.textsecure.api.messages.TextSecureAttachmentStream; import org.whispersystems.textsecure.api.messages.TextSecureGroup; import org.whispersystems.textsecure.api.messages.TextSecureMessage; -import org.whispersystems.textsecure.api.crypto.TextSecureCipher; -import org.whispersystems.textsecure.api.crypto.UntrustedIdentityException; import org.whispersystems.textsecure.push.MismatchedDevices; import org.whispersystems.textsecure.push.OutgoingPushMessage; import org.whispersystems.textsecure.push.OutgoingPushMessageList; @@ -48,17 +47,19 @@ public class TextSecureMessageSender { private final AxolotlStore store; private final Optional eventListener; - public TextSecureMessageSender(Context context, String url, - PushServiceSocket.TrustStore trustStore, - String user, String password, - AxolotlStore store, + public TextSecureMessageSender(String url, PushServiceSocket.TrustStore trustStore, + String user, String password, AxolotlStore store, Optional eventListener) { - this.socket = new PushServiceSocket(context, url, trustStore, user, password); + this.socket = new PushServiceSocket(url, trustStore, user, password); this.store = store; this.eventListener = eventListener; } + public void sendDeliveryReceipt(PushAddress recipient, long messageId) throws IOException { + this.socket.sendReceipt(recipient.getNumber(), messageId, recipient.getRelay()); + } + public void sendMessage(PushAddress recipient, TextSecureMessage message) throws UntrustedIdentityException, IOException { diff --git a/library/src/org/whispersystems/textsecure/push/PushAddress.java b/library/src/org/whispersystems/textsecure/push/PushAddress.java index fe864e86b4..6ffb9ef735 100644 --- a/library/src/org/whispersystems/textsecure/push/PushAddress.java +++ b/library/src/org/whispersystems/textsecure/push/PushAddress.java @@ -1,8 +1,5 @@ package org.whispersystems.textsecure.push; -import android.content.Context; - -import org.whispersystems.textsecure.directory.Directory; import org.whispersystems.textsecure.storage.RecipientDevice; public class PushAddress extends RecipientDevice { @@ -24,9 +21,4 @@ public class PushAddress extends RecipientDevice { return relay; } - public static PushAddress create(Context context, long recipientId, String e164number, int deviceId) { - String relay = Directory.getInstance(context).getRelay(e164number); - return new PushAddress(recipientId, e164number, deviceId, relay); - } - } diff --git a/library/src/org/whispersystems/textsecure/push/PushServiceSocket.java b/library/src/org/whispersystems/textsecure/push/PushServiceSocket.java index bd0615396b..789a109cf0 100644 --- a/library/src/org/whispersystems/textsecure/push/PushServiceSocket.java +++ b/library/src/org/whispersystems/textsecure/push/PushServiceSocket.java @@ -16,7 +16,6 @@ */ package org.whispersystems.textsecure.push; -import android.content.Context; import android.util.Log; import com.google.thoughtcrimegson.Gson; @@ -88,16 +87,14 @@ public class PushServiceSocket { private static final boolean ENFORCE_SSL = true; - private final Context context; private final String serviceUrl; private final String localNumber; private final String password; private final TrustManager[] trustManagers; - public PushServiceSocket(Context context, String serviceUrl, TrustStore trustStore, + public PushServiceSocket(String serviceUrl, TrustStore trustStore, String localNumber, String password) { - this.context = context.getApplicationContext(); this.serviceUrl = serviceUrl; this.localNumber = localNumber; this.password = password; diff --git a/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java b/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java index 318099d7fa..da77fcd705 100644 --- a/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java +++ b/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java @@ -54,8 +54,9 @@ import com.google.android.gms.gcm.GoogleCloudMessaging; import org.thoughtcrime.securesms.components.OutgoingSmsPreference; import org.thoughtcrime.securesms.contacts.ContactAccessor; import org.thoughtcrime.securesms.contacts.ContactIdentityManager; +import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.crypto.MasterSecretUtil; -import org.thoughtcrime.securesms.push.PushServiceSocketFactory; +import org.thoughtcrime.securesms.push.TextSecureCommunicationFactory; import org.thoughtcrime.securesms.service.KeyCachingService; import org.thoughtcrime.securesms.util.Dialogs; import org.thoughtcrime.securesms.util.DynamicLanguage; @@ -64,9 +65,9 @@ import org.thoughtcrime.securesms.util.MemoryCleaner; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.Trimmer; import org.thoughtcrime.securesms.util.Util; -import org.thoughtcrime.securesms.crypto.MasterSecret; +import org.whispersystems.libaxolotl.util.guava.Optional; +import org.whispersystems.textsecure.api.TextSecureAccountManager; import org.whispersystems.textsecure.push.exceptions.AuthorizationFailedException; -import org.whispersystems.textsecure.push.PushServiceSocket; import java.io.IOException; @@ -362,10 +363,10 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA @Override protected Integer doInBackground(Void... params) { try { - Context context = getActivity(); - PushServiceSocket socket = PushServiceSocketFactory.create(context); + Context context = getActivity(); + TextSecureAccountManager accountManager = TextSecureCommunicationFactory.createManager(context); - socket.unregisterGcmId(); + accountManager.setGcmId(Optional.absent()); GoogleCloudMessaging.getInstance(context).unregister(); return SUCCESS; diff --git a/src/org/thoughtcrime/securesms/GroupCreateActivity.java b/src/org/thoughtcrime/securesms/GroupCreateActivity.java index 4451b541ab..75d509fc6a 100644 --- a/src/org/thoughtcrime/securesms/GroupCreateActivity.java +++ b/src/org/thoughtcrime/securesms/GroupCreateActivity.java @@ -62,10 +62,9 @@ import org.thoughtcrime.securesms.util.SelectedRecipientsAdapter; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.crypto.MasterSecret; -import org.whispersystems.textsecure.directory.Directory; -import org.whispersystems.textsecure.directory.NotInDirectoryException; +import org.thoughtcrime.securesms.database.TextSecureDirectory; +import org.thoughtcrime.securesms.database.NotInDirectoryException; import org.whispersystems.textsecure.util.InvalidNumberException; -import org.whispersystems.textsecure.util.ListenableFutureTask; import java.io.ByteArrayOutputStream; import java.io.FileNotFoundException; @@ -77,7 +76,6 @@ import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; -import java.util.concurrent.ExecutionException; import ws.com.google.android.mms.MmsException; @@ -171,7 +169,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity { private static boolean isActiveInDirectory(Context context, Recipient recipient) { try { - if (!Directory.getInstance(context).isActiveNumber(Util.canonicalizeNumber(context, recipient.getNumber()))) { + if (!TextSecureDirectory.getInstance(context).isActiveNumber(Util.canonicalizeNumber(context, recipient.getNumber()))) { return false; } } catch (NotInDirectoryException e) { diff --git a/src/org/thoughtcrime/securesms/RegistrationProgressActivity.java b/src/org/thoughtcrime/securesms/RegistrationProgressActivity.java index eb28f51693..fc7083558e 100644 --- a/src/org/thoughtcrime/securesms/RegistrationProgressActivity.java +++ b/src/org/thoughtcrime/securesms/RegistrationProgressActivity.java @@ -30,13 +30,13 @@ import android.widget.TextView; import android.widget.Toast; -import org.thoughtcrime.securesms.push.PushServiceSocketFactory; +import org.thoughtcrime.securesms.crypto.MasterSecret; +import org.thoughtcrime.securesms.push.TextSecureCommunicationFactory; import org.thoughtcrime.securesms.service.RegistrationService; import org.thoughtcrime.securesms.util.Dialogs; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.thoughtcrime.securesms.crypto.MasterSecret; +import org.whispersystems.textsecure.api.TextSecureAccountManager; import org.whispersystems.textsecure.push.exceptions.ExpectationFailedException; -import org.whispersystems.textsecure.push.PushServiceSocket; import org.whispersystems.textsecure.push.exceptions.RateLimitException; import org.whispersystems.textsecure.util.PhoneNumberFormatter; import org.whispersystems.textsecure.util.Util; @@ -514,9 +514,11 @@ public class RegistrationProgressActivity extends ActionBarActivity { @Override protected Integer doInBackground(Void... params) { try { - PushServiceSocket socket = PushServiceSocketFactory.create(context, e164number, password); + TextSecureAccountManager accountManager = TextSecureCommunicationFactory.createManager(context); int registrationId = TextSecurePreferences.getLocalRegistrationId(context); - socket.verifyAccount(code, signalingKey, true, registrationId); + + accountManager.verifyAccount(code, signalingKey, true, registrationId); + return SUCCESS; } catch (ExpectationFailedException e) { Log.w("RegistrationProgressActivity", e); @@ -605,8 +607,8 @@ public class RegistrationProgressActivity extends ActionBarActivity { @Override protected Integer doInBackground(Void... params) { try { - PushServiceSocket socket = PushServiceSocketFactory.create(context, e164number, password); - socket.createAccount(true); + TextSecureAccountManager accountManager = TextSecureCommunicationFactory.createManager(context); + accountManager.requestVoiceVerificationCode(); return SUCCESS; } catch (RateLimitException e) { diff --git a/src/org/thoughtcrime/securesms/contacts/ContactAccessor.java b/src/org/thoughtcrime/securesms/contacts/ContactAccessor.java index 1d20354dec..a44edc31f6 100644 --- a/src/org/thoughtcrime/securesms/contacts/ContactAccessor.java +++ b/src/org/thoughtcrime/securesms/contacts/ContactAccessor.java @@ -32,7 +32,7 @@ import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.telephony.PhoneNumberUtils; -import org.whispersystems.textsecure.directory.Directory; +import org.thoughtcrime.securesms.database.TextSecureDirectory; import java.util.ArrayList; import java.util.Collection; @@ -94,7 +94,7 @@ public class ContactAccessor { final ContentResolver resolver = context.getContentResolver(); final String[] inProjection = new String[]{PhoneLookup._ID, PhoneLookup.DISPLAY_NAME}; - List pushNumbers = Directory.getInstance(context).getActiveNumbers(); + List pushNumbers = TextSecureDirectory.getInstance(context).getActiveNumbers(); final Collection lookupData = new ArrayList(pushNumbers.size()); for (String pushNumber : pushNumbers) { diff --git a/library/src/org/whispersystems/textsecure/directory/NotInDirectoryException.java b/src/org/thoughtcrime/securesms/database/NotInDirectoryException.java similarity index 55% rename from library/src/org/whispersystems/textsecure/directory/NotInDirectoryException.java rename to src/org/thoughtcrime/securesms/database/NotInDirectoryException.java index 45299ee870..92a150e0c0 100644 --- a/library/src/org/whispersystems/textsecure/directory/NotInDirectoryException.java +++ b/src/org/thoughtcrime/securesms/database/NotInDirectoryException.java @@ -1,4 +1,4 @@ -package org.whispersystems.textsecure.directory; +package org.thoughtcrime.securesms.database; public class NotInDirectoryException extends Throwable { } diff --git a/library/src/org/whispersystems/textsecure/directory/Directory.java b/src/org/thoughtcrime/securesms/database/TextSecureDirectory.java similarity index 96% rename from library/src/org/whispersystems/textsecure/directory/Directory.java rename to src/org/thoughtcrime/securesms/database/TextSecureDirectory.java index 735a1e3d5a..9058fea725 100644 --- a/library/src/org/whispersystems/textsecure/directory/Directory.java +++ b/src/org/thoughtcrime/securesms/database/TextSecureDirectory.java @@ -1,4 +1,4 @@ -package org.whispersystems.textsecure.directory; +package org.thoughtcrime.securesms.database; import android.content.ContentValues; import android.content.Context; @@ -19,7 +19,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -public class Directory { +public class TextSecureDirectory { private static final int INTRODUCED_CHANGE_FROM_TOKEN_TO_E164_NUMBER = 2; @@ -41,13 +41,13 @@ public class Directory { TIMESTAMP + " INTEGER);"; private static final Object instanceLock = new Object(); - private static volatile Directory instance; + private static volatile TextSecureDirectory instance; - public static Directory getInstance(Context context) { + public static TextSecureDirectory getInstance(Context context) { if (instance == null) { synchronized (instanceLock) { if (instance == null) { - instance = new Directory(context); + instance = new TextSecureDirectory(context); } } } @@ -58,7 +58,7 @@ public class Directory { private final DatabaseHelper databaseHelper; private final Context context; - private Directory(Context context) { + private TextSecureDirectory(Context context) { this.context = context; this.databaseHelper = new DatabaseHelper(context, DATABASE_NAME, null, DATABASE_VERSION); } diff --git a/src/org/thoughtcrime/securesms/jobs/AttachmentDownloadJob.java b/src/org/thoughtcrime/securesms/jobs/AttachmentDownloadJob.java index ab138a62e7..a04468cb3d 100644 --- a/src/org/thoughtcrime/securesms/jobs/AttachmentDownloadJob.java +++ b/src/org/thoughtcrime/securesms/jobs/AttachmentDownloadJob.java @@ -10,7 +10,7 @@ import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.EncryptingPartDatabase; import org.thoughtcrime.securesms.database.PartDatabase; import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement; -import org.thoughtcrime.securesms.push.TextSecureMessageReceiverFactory; +import org.thoughtcrime.securesms.push.TextSecureCommunicationFactory; import org.thoughtcrime.securesms.util.Util; import org.whispersystems.jobqueue.JobParameters; import org.whispersystems.jobqueue.requirements.NetworkRequirement; @@ -89,12 +89,13 @@ public class AttachmentDownloadJob extends MasterSecretJob { private void retrievePart(MasterSecret masterSecret, PduPart part, long messageId, long partId) throws IOException { - TextSecureMessageReceiver receiver = TextSecureMessageReceiverFactory.create(context, masterSecret); + TextSecureMessageReceiver receiver = TextSecureCommunicationFactory.createReceiver(context, masterSecret); EncryptingPartDatabase database = DatabaseFactory.getEncryptingPartDatabase(context, masterSecret); File attachmentFile = null; try { attachmentFile = createTempFile(); + TextSecureAttachmentPointer pointer = createAttachmentPointer(masterSecret, part); InputStream attachment = receiver.retrieveAttachment(pointer, attachmentFile); diff --git a/src/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java b/src/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java index a243d71322..4fd13e8496 100644 --- a/src/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java +++ b/src/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java @@ -4,16 +4,18 @@ import android.content.Context; import android.graphics.Bitmap; import android.util.Log; +import org.thoughtcrime.securesms.Release; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.GroupDatabase; import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement; -import org.thoughtcrime.securesms.push.PushServiceSocketFactory; +import org.thoughtcrime.securesms.push.TextSecurePushTrustStore; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientFactory; import org.thoughtcrime.securesms.recipients.RecipientFormattingException; import org.thoughtcrime.securesms.util.BitmapDecodingException; import org.thoughtcrime.securesms.util.BitmapUtil; import org.thoughtcrime.securesms.util.GroupUtil; +import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.jobqueue.JobParameters; import org.whispersystems.jobqueue.requirements.NetworkRequirement; import org.whispersystems.libaxolotl.InvalidMessageException; @@ -94,8 +96,12 @@ public class AvatarDownloadJob extends MasterSecretJob { } private File downloadAttachment(String relay, long contentLocation) throws IOException { - PushServiceSocket socket = PushServiceSocketFactory.create(context); - File destination = File.createTempFile("avatar", "tmp"); + PushServiceSocket socket = new PushServiceSocket(Release.PUSH_URL, + new TextSecurePushTrustStore(context), + TextSecurePreferences.getLocalNumber(context), + TextSecurePreferences.getPushServerPassword(context)); + + File destination = File.createTempFile("avatar", "tmp"); destination.deleteOnExit(); diff --git a/src/org/thoughtcrime/securesms/jobs/CleanPreKeysJob.java b/src/org/thoughtcrime/securesms/jobs/CleanPreKeysJob.java new file mode 100644 index 0000000000..55b817aaf4 --- /dev/null +++ b/src/org/thoughtcrime/securesms/jobs/CleanPreKeysJob.java @@ -0,0 +1,135 @@ +package org.thoughtcrime.securesms.jobs; + +import android.content.Context; +import android.util.Log; + +import org.thoughtcrime.securesms.crypto.MasterSecret; +import org.thoughtcrime.securesms.crypto.storage.TextSecureAxolotlStore; +import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement; +import org.thoughtcrime.securesms.push.TextSecureCommunicationFactory; +import org.thoughtcrime.securesms.util.VisibleForTesting; +import org.whispersystems.jobqueue.JobParameters; +import org.whispersystems.libaxolotl.InvalidKeyIdException; +import org.whispersystems.libaxolotl.state.SignedPreKeyRecord; +import org.whispersystems.libaxolotl.state.SignedPreKeyStore; +import org.whispersystems.textsecure.api.TextSecureAccountManager; +import org.whispersystems.textsecure.push.SignedPreKeyEntity; +import org.whispersystems.textsecure.push.exceptions.NonSuccessfulResponseCodeException; +import org.whispersystems.textsecure.push.exceptions.PushNetworkException; + +import java.io.IOException; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +public class CleanPreKeysJob extends MasterSecretJob { + + private static final String TAG = CleanPreKeysJob.class.getSimpleName(); + + private static final int ARCHIVE_AGE_DAYS = 15; + + public CleanPreKeysJob(Context context) { + super(context, JobParameters.newBuilder() + .withGroupId(CleanPreKeysJob.class.getSimpleName()) + .withRequirement(new MasterSecretRequirement(context)) + .withRetryCount(5) + .create()); + } + + @Override + public void onAdded() { + + } + + @Override + public void onRun() throws RequirementNotMetException, IOException { + try { + MasterSecret masterSecret = getMasterSecret(); + SignedPreKeyStore signedPreKeyStore = createSignedPreKeyStore(context, masterSecret); + TextSecureAccountManager accountManager = createAccountManager(context); + + SignedPreKeyEntity currentSignedPreKey = accountManager.getSignedPreKey(); + + if (currentSignedPreKey == null) return; + + SignedPreKeyRecord currentRecord = signedPreKeyStore.loadSignedPreKey(currentSignedPreKey.getKeyId()); + List allRecords = signedPreKeyStore.loadSignedPreKeys(); + List oldRecords = removeRecordFrom(currentRecord, allRecords); + + Collections.sort(oldRecords, new SignedPreKeySorter()); + + Log.w(TAG, "Old signed prekey record count: " + oldRecords.size()); + + if (oldRecords.size() < 2) { + return; + } + + SignedPreKeyRecord latestRecord = oldRecords.get(0); + long latestRecordArchiveDuration = System.currentTimeMillis() - latestRecord.getTimestamp(); + + if (latestRecordArchiveDuration >= TimeUnit.DAYS.toMillis(ARCHIVE_AGE_DAYS)) { + Iterator iterator = oldRecords.iterator(); + iterator.next(); + + while (iterator.hasNext()) { + SignedPreKeyRecord expiredRecord = iterator.next(); + Log.w(TAG, "Removing signed prekey record: " + expiredRecord.getId() + " with timestamp: " + expiredRecord.getTimestamp()); + + signedPreKeyStore.removeSignedPreKey(expiredRecord.getId()); + } + } + } catch (InvalidKeyIdException e) { + Log.w(TAG, e); + } + } + + @Override + public boolean onShouldRetry(Throwable throwable) { + if (throwable instanceof RequirementNotMetException) return true; + if (throwable instanceof NonSuccessfulResponseCodeException) return false; + if (throwable instanceof PushNetworkException) return true; + return false; + } + + @Override + public void onCanceled() { + Log.w(TAG, "Failed to execute clean signed prekeys task."); + } + + private List removeRecordFrom(SignedPreKeyRecord currentRecord, + List records) + + { + List others = new LinkedList<>(); + + for (SignedPreKeyRecord record : records) { + if (record.getId() != currentRecord.getId()) { + others.add(record); + } + } + + return others; + } + + @VisibleForTesting + protected TextSecureAccountManager createAccountManager(Context context) { + return TextSecureCommunicationFactory.createManager(context); + } + + protected SignedPreKeyStore createSignedPreKeyStore(Context context, MasterSecret masterSecret) { + return new TextSecureAxolotlStore(context, masterSecret); + } + + private static class SignedPreKeySorter implements Comparator { + @Override + public int compare(SignedPreKeyRecord lhs, SignedPreKeyRecord rhs) { + if (lhs.getTimestamp() < rhs.getTimestamp()) return -1; + else if (lhs.getTimestamp() > rhs.getTimestamp()) return 1; + else return 0; + } + } + +} diff --git a/src/org/thoughtcrime/securesms/jobs/CreateSignedPreKeyJob.java b/src/org/thoughtcrime/securesms/jobs/CreateSignedPreKeyJob.java index 67c3c01e46..d6aa1b3eea 100644 --- a/src/org/thoughtcrime/securesms/jobs/CreateSignedPreKeyJob.java +++ b/src/org/thoughtcrime/securesms/jobs/CreateSignedPreKeyJob.java @@ -4,7 +4,9 @@ import android.content.Context; import android.util.Log; import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; -import org.thoughtcrime.securesms.push.PushServiceSocketFactory; +import org.thoughtcrime.securesms.crypto.MasterSecret; +import org.thoughtcrime.securesms.crypto.PreKeyUtil; +import org.thoughtcrime.securesms.push.TextSecureCommunicationFactory; import org.thoughtcrime.securesms.util.ParcelUtil; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.jobqueue.EncryptionKeys; @@ -12,9 +14,7 @@ import org.whispersystems.jobqueue.JobParameters; import org.whispersystems.jobqueue.requirements.NetworkRequirement; import org.whispersystems.libaxolotl.IdentityKeyPair; import org.whispersystems.libaxolotl.state.SignedPreKeyRecord; -import org.thoughtcrime.securesms.crypto.MasterSecret; -import org.thoughtcrime.securesms.crypto.PreKeyUtil; -import org.whispersystems.textsecure.push.PushServiceSocket; +import org.whispersystems.textsecure.api.TextSecureAccountManager; import java.io.IOException; @@ -43,11 +43,11 @@ public class CreateSignedPreKeyJob extends ContextJob { return; } - IdentityKeyPair identityKeyPair = IdentityKeyUtil.getIdentityKeyPair(context, masterSecret); - SignedPreKeyRecord signedPreKeyRecord = PreKeyUtil.generateSignedPreKey(context, masterSecret, identityKeyPair); - PushServiceSocket socket = PushServiceSocketFactory.create(context); + IdentityKeyPair identityKeyPair = IdentityKeyUtil.getIdentityKeyPair(context, masterSecret); + SignedPreKeyRecord signedPreKeyRecord = PreKeyUtil.generateSignedPreKey(context, masterSecret, identityKeyPair); + TextSecureAccountManager accountManager = TextSecureCommunicationFactory.createManager(context); - socket.setCurrentSignedPreKey(signedPreKeyRecord); + accountManager.setSignedPreKey(signedPreKeyRecord); TextSecurePreferences.setSignedPreKeyRegistered(context, true); } diff --git a/src/org/thoughtcrime/securesms/jobs/DeliveryReceiptJob.java b/src/org/thoughtcrime/securesms/jobs/DeliveryReceiptJob.java index edb87ca879..f883464fde 100644 --- a/src/org/thoughtcrime/securesms/jobs/DeliveryReceiptJob.java +++ b/src/org/thoughtcrime/securesms/jobs/DeliveryReceiptJob.java @@ -3,13 +3,19 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; import android.util.Log; -import org.thoughtcrime.securesms.push.PushServiceSocketFactory; +import org.thoughtcrime.securesms.Release; +import org.thoughtcrime.securesms.push.TextSecurePushTrustStore; +import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.jobqueue.JobParameters; import org.whispersystems.jobqueue.requirements.NetworkRequirement; -import org.whispersystems.textsecure.push.PushServiceSocket; +import org.whispersystems.libaxolotl.util.guava.Optional; +import org.whispersystems.textsecure.api.TextSecureMessageSender; +import org.whispersystems.textsecure.push.PushAddress; import org.whispersystems.textsecure.push.exceptions.NonSuccessfulResponseCodeException; import org.whispersystems.textsecure.push.exceptions.PushNetworkException; +import java.io.IOException; + public class DeliveryReceiptJob extends ContextJob { private static final String TAG = DeliveryReceiptJob.class.getSimpleName(); @@ -34,10 +40,17 @@ public class DeliveryReceiptJob extends ContextJob { public void onAdded() {} @Override - public void onRun() throws Throwable { + public void onRun() throws IOException { Log.w("DeliveryReceiptJob", "Sending delivery receipt..."); - PushServiceSocket socket = PushServiceSocketFactory.create(context); - socket.sendReceipt(destination, timestamp, relay); + TextSecureMessageSender messageSender = + new TextSecureMessageSender(Release.PUSH_URL, + new TextSecurePushTrustStore(context), + TextSecurePreferences.getLocalNumber(context), + TextSecurePreferences.getPushServerPassword(context), + null, Optional.absent()); + + PushAddress pushAddress = new PushAddress(-1, destination, 1, relay); + messageSender.sendDeliveryReceipt(pushAddress, timestamp); } @Override diff --git a/src/org/thoughtcrime/securesms/jobs/GcmRefreshJob.java b/src/org/thoughtcrime/securesms/jobs/GcmRefreshJob.java index 07ed043217..a9a559ad85 100644 --- a/src/org/thoughtcrime/securesms/jobs/GcmRefreshJob.java +++ b/src/org/thoughtcrime/securesms/jobs/GcmRefreshJob.java @@ -8,11 +8,12 @@ import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GooglePlayServicesUtil; import com.google.android.gms.gcm.GoogleCloudMessaging; -import org.thoughtcrime.securesms.push.PushServiceSocketFactory; +import org.thoughtcrime.securesms.push.TextSecureCommunicationFactory; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.jobqueue.JobParameters; import org.whispersystems.jobqueue.requirements.NetworkRequirement; -import org.whispersystems.textsecure.push.PushServiceSocket; +import org.whispersystems.libaxolotl.util.guava.Optional; +import org.whispersystems.textsecure.api.TextSecureAccountManager; import org.whispersystems.textsecure.push.exceptions.NonSuccessfulResponseCodeException; public class GcmRefreshJob extends ContextJob { @@ -40,10 +41,11 @@ public class GcmRefreshJob extends ContextJob { Toast.makeText(context, "Unable to register with GCM!", Toast.LENGTH_LONG).show(); } - String gcmId = GoogleCloudMessaging.getInstance(context).register(REGISTRATION_ID); - PushServiceSocket socket = PushServiceSocketFactory.create(context); + String gcmId = GoogleCloudMessaging.getInstance(context).register(REGISTRATION_ID); + TextSecureAccountManager accountManager = TextSecureCommunicationFactory.createManager(context); + + accountManager.setGcmId(Optional.of(gcmId)); - socket.registerGcmId(gcmId); TextSecurePreferences.setGcmRegistrationId(context, gcmId); } } diff --git a/src/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java index 8230c3c880..b7e68a0faa 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java @@ -10,7 +10,7 @@ import org.thoughtcrime.securesms.database.MmsSmsColumns; import org.thoughtcrime.securesms.database.NoSuchMessageException; import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement; import org.thoughtcrime.securesms.mms.PartParser; -import org.thoughtcrime.securesms.push.TextSecureMessageSenderFactory; +import org.thoughtcrime.securesms.push.TextSecureCommunicationFactory; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientFormattingException; import org.thoughtcrime.securesms.recipients.Recipients; @@ -106,7 +106,7 @@ public class PushGroupSendJob extends PushSendJob { private void deliver(MasterSecret masterSecret, SendReq message) throws IOException, RecipientFormattingException, InvalidNumberException, EncapsulatedExceptions { - TextSecureMessageSender messageSender = TextSecureMessageSenderFactory.create(context, masterSecret); + TextSecureMessageSender messageSender = TextSecureCommunicationFactory.createSender(context, masterSecret); byte[] groupId = GroupUtil.getDecodedId(message.getTo()[0].getString()); Recipients recipients = DatabaseFactory.getGroupDatabase(context).getGroupMembers(groupId, false); List addresses = getPushAddresses(recipients); diff --git a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java index 9c2d1dc53c..279382bc44 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java @@ -10,7 +10,7 @@ import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.MmsDatabase; import org.thoughtcrime.securesms.database.NoSuchMessageException; import org.thoughtcrime.securesms.mms.PartParser; -import org.thoughtcrime.securesms.push.TextSecureMessageSenderFactory; +import org.thoughtcrime.securesms.push.TextSecureCommunicationFactory; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientFactory; import org.thoughtcrime.securesms.recipients.RecipientFormattingException; @@ -98,7 +98,7 @@ public class PushMediaSendJob extends PushSendJob { InsecureFallbackApprovalException, UntrustedIdentityException { MmsDatabase database = DatabaseFactory.getMmsDatabase(context); - TextSecureMessageSender messageSender = TextSecureMessageSenderFactory.create(context, masterSecret); + TextSecureMessageSender messageSender = TextSecureCommunicationFactory.createSender(context, masterSecret); String destination = message.getTo()[0].getString(); boolean isSmsFallbackSupported = isSmsFallbackSupported(context, destination); diff --git a/src/org/thoughtcrime/securesms/jobs/PushReceiveJob.java b/src/org/thoughtcrime/securesms/jobs/PushReceiveJob.java index cc8d7d715b..8ee5370b6c 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushReceiveJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushReceiveJob.java @@ -10,8 +10,8 @@ import org.whispersystems.jobqueue.JobManager; import org.whispersystems.jobqueue.JobParameters; import org.whispersystems.libaxolotl.InvalidVersionException; import org.whispersystems.textsecure.api.messages.TextSecureEnvelope; -import org.whispersystems.textsecure.directory.Directory; -import org.whispersystems.textsecure.directory.NotInDirectoryException; +import org.thoughtcrime.securesms.database.TextSecureDirectory; +import org.thoughtcrime.securesms.database.NotInDirectoryException; import org.whispersystems.textsecure.push.ContactTokenDetails; import java.io.IOException; @@ -40,7 +40,7 @@ public class PushReceiveJob extends ContextJob { TextSecureEnvelope envelope = new TextSecureEnvelope(data, sessionKey); if (!isActiveNumber(context, envelope.getSource())) { - Directory directory = Directory.getInstance(context); + TextSecureDirectory directory = TextSecureDirectory.getInstance(context); ContactTokenDetails contactTokenDetails = new ContactTokenDetails(); contactTokenDetails.setNumber(envelope.getSource()); @@ -85,7 +85,7 @@ public class PushReceiveJob extends ContextJob { boolean isActiveNumber; try { - isActiveNumber = Directory.getInstance(context).isActiveNumber(e164number); + isActiveNumber = TextSecureDirectory.getInstance(context).isActiveNumber(e164number); } catch (NotInDirectoryException e) { isActiveNumber = false; } diff --git a/src/org/thoughtcrime/securesms/jobs/PushSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushSendJob.java index 2025796a2d..71dc10dbf7 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushSendJob.java @@ -15,7 +15,7 @@ import org.whispersystems.jobqueue.JobParameters; import org.whispersystems.jobqueue.requirements.NetworkRequirement; import org.whispersystems.textsecure.api.messages.TextSecureAttachment; import org.whispersystems.textsecure.api.messages.TextSecureAttachmentStream; -import org.whispersystems.textsecure.directory.Directory; +import org.thoughtcrime.securesms.database.TextSecureDirectory; import org.whispersystems.textsecure.push.PushAddress; import org.whispersystems.textsecure.util.InvalidNumberException; @@ -57,13 +57,13 @@ public abstract class PushSendJob extends MasterSecretJob { return false; } - Directory directory = Directory.getInstance(context); + TextSecureDirectory directory = TextSecureDirectory.getInstance(context); return directory.isSmsFallbackSupported(destination); } protected PushAddress getPushAddress(Recipient recipient) throws InvalidNumberException { String e164number = Util.canonicalizeNumber(context, recipient.getNumber()); - String relay = Directory.getInstance(context).getRelay(e164number); + String relay = TextSecureDirectory.getInstance(context).getRelay(e164number); return new PushAddress(recipient.getRecipientId(), e164number, 1, relay); } diff --git a/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java index 787406b89c..eb926d8426 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java @@ -11,7 +11,7 @@ import org.thoughtcrime.securesms.database.EncryptingSmsDatabase; import org.thoughtcrime.securesms.database.NoSuchMessageException; import org.thoughtcrime.securesms.database.model.SmsMessageRecord; import org.thoughtcrime.securesms.notifications.MessageNotifier; -import org.thoughtcrime.securesms.push.TextSecureMessageSenderFactory; +import org.thoughtcrime.securesms.push.TextSecureCommunicationFactory; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipients; import org.thoughtcrime.securesms.sms.IncomingIdentityUpdateMessage; @@ -85,7 +85,7 @@ public class PushTextSendJob extends PushSendJob { try { PushAddress address = getPushAddress(message.getIndividualRecipient()); - TextSecureMessageSender messageSender = TextSecureMessageSenderFactory.create(context, masterSecret); + TextSecureMessageSender messageSender = TextSecureCommunicationFactory.createSender(context, masterSecret); if (message.isEndSession()) { messageSender.sendMessage(address, new TextSecureMessage(message.getDateSent(), null, diff --git a/src/org/thoughtcrime/securesms/jobs/RefreshPreKeysJob.java b/src/org/thoughtcrime/securesms/jobs/RefreshPreKeysJob.java new file mode 100644 index 0000000000..105dc0f834 --- /dev/null +++ b/src/org/thoughtcrime/securesms/jobs/RefreshPreKeysJob.java @@ -0,0 +1,85 @@ +package org.thoughtcrime.securesms.jobs; + +import android.content.Context; +import android.util.Log; + +import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; +import org.thoughtcrime.securesms.crypto.MasterSecret; +import org.thoughtcrime.securesms.crypto.PreKeyUtil; +import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement; +import org.thoughtcrime.securesms.push.TextSecureCommunicationFactory; +import org.thoughtcrime.securesms.util.TextSecurePreferences; +import org.whispersystems.jobqueue.JobParameters; +import org.whispersystems.jobqueue.requirements.NetworkRequirement; +import org.whispersystems.libaxolotl.IdentityKeyPair; +import org.whispersystems.libaxolotl.state.PreKeyRecord; +import org.whispersystems.libaxolotl.state.SignedPreKeyRecord; +import org.whispersystems.textsecure.api.TextSecureAccountManager; +import org.whispersystems.textsecure.push.PushServiceSocket; +import org.whispersystems.textsecure.push.exceptions.NonSuccessfulResponseCodeException; +import org.whispersystems.textsecure.push.exceptions.PushNetworkException; + +import java.io.IOException; +import java.util.List; + +public class RefreshPreKeysJob extends MasterSecretJob { + + private static final String TAG = RefreshPreKeysJob.class.getSimpleName(); + + private static final int PREKEY_MINIMUM = 10; + + public RefreshPreKeysJob(Context context) { + super(context, JobParameters.newBuilder() + .withGroupId(RefreshPreKeysJob.class.getSimpleName()) + .withRequirement(new NetworkRequirement(context)) + .withRequirement(new MasterSecretRequirement(context)) + .withRetryCount(5) + .create()); + } + + @Override + public void onAdded() { + + } + + @Override + public void onRun() throws RequirementNotMetException, IOException { + if (!TextSecurePreferences.isPushRegistered(context)) return; + + MasterSecret masterSecret = getMasterSecret(); + TextSecureAccountManager accountManager = TextSecureCommunicationFactory.createManager(context); + int availableKeys = accountManager.getPreKeysCount(); + + if (availableKeys >= PREKEY_MINIMUM && TextSecurePreferences.isSignedPreKeyRegistered(context)) { + Log.w(TAG, "Available keys sufficient: " + availableKeys); + return; + } + + List preKeyRecords = PreKeyUtil.generatePreKeys(context, masterSecret); + PreKeyRecord lastResortKeyRecord = PreKeyUtil.generateLastResortKey(context, masterSecret); + IdentityKeyPair identityKey = IdentityKeyUtil.getIdentityKeyPair(context, masterSecret); + SignedPreKeyRecord signedPreKeyRecord = PreKeyUtil.generateSignedPreKey(context, masterSecret, identityKey); + + Log.w(TAG, "Registering new prekeys..."); + + accountManager.setPreKeys(identityKey.getPublicKey(), lastResortKeyRecord, signedPreKeyRecord, preKeyRecords); + + TextSecurePreferences.setSignedPreKeyRegistered(context, true); +// PreKeyService.initiateClean(context, masterSecret); + } + + @Override + public boolean onShouldRetry(Throwable throwable) { + if (throwable instanceof RequirementNotMetException) return true; + if (throwable instanceof NonSuccessfulResponseCodeException) return false; + if (throwable instanceof PushNetworkException) return true; + + return false; + } + + @Override + public void onCanceled() { + + } + +} diff --git a/src/org/thoughtcrime/securesms/push/PushServiceSocketFactory.java b/src/org/thoughtcrime/securesms/push/PushServiceSocketFactory.java deleted file mode 100644 index 07db068e5e..0000000000 --- a/src/org/thoughtcrime/securesms/push/PushServiceSocketFactory.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.thoughtcrime.securesms.push; - -import android.content.Context; - -import org.thoughtcrime.securesms.Release; -import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.whispersystems.textsecure.push.PushServiceSocket; - -public class PushServiceSocketFactory { - - public static PushServiceSocket create(Context context, String number, String password) { - return new PushServiceSocket(context, Release.PUSH_URL, new TextSecurePushTrustStore(context), - number, password); - } - - public static PushServiceSocket create(Context context) { - return create(context, - TextSecurePreferences.getLocalNumber(context), - TextSecurePreferences.getPushServerPassword(context)); - } - -} diff --git a/src/org/thoughtcrime/securesms/push/TextSecureMessageSenderFactory.java b/src/org/thoughtcrime/securesms/push/TextSecureCommunicationFactory.java similarity index 52% rename from src/org/thoughtcrime/securesms/push/TextSecureMessageSenderFactory.java rename to src/org/thoughtcrime/securesms/push/TextSecureCommunicationFactory.java index 6019bc93a6..f39de70fba 100644 --- a/src/org/thoughtcrime/securesms/push/TextSecureMessageSenderFactory.java +++ b/src/org/thoughtcrime/securesms/push/TextSecureCommunicationFactory.java @@ -11,13 +11,15 @@ import org.thoughtcrime.securesms.recipients.RecipientFactory; import org.thoughtcrime.securesms.recipients.Recipients; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.libaxolotl.util.guava.Optional; +import org.whispersystems.textsecure.api.TextSecureAccountManager; +import org.whispersystems.textsecure.api.TextSecureMessageReceiver; import org.whispersystems.textsecure.api.TextSecureMessageSender; import static org.whispersystems.textsecure.api.TextSecureMessageSender.EventListener; -public class TextSecureMessageSenderFactory { - public static TextSecureMessageSender create(Context context, MasterSecret masterSecret) { - return new TextSecureMessageSender(context, Release.PUSH_URL, +public class TextSecureCommunicationFactory { + public static TextSecureMessageSender createSender(Context context, MasterSecret masterSecret) { + return new TextSecureMessageSender(Release.PUSH_URL, new TextSecurePushTrustStore(context), TextSecurePreferences.getLocalNumber(context), TextSecurePreferences.getPushServerPassword(context), @@ -25,6 +27,27 @@ public class TextSecureMessageSenderFactory { Optional.of((EventListener)new SecurityEventListener(context))); } + public static TextSecureMessageReceiver createReceiver(Context context, MasterSecret masterSecret) { + return new TextSecureMessageReceiver(TextSecurePreferences.getSignalingKey(context), + Release.PUSH_URL, + new TextSecurePushTrustStore(context), + TextSecurePreferences.getLocalNumber(context), + TextSecurePreferences.getPushServerPassword(context), + new TextSecureAxolotlStore(context, masterSecret)); + } + + public static TextSecureAccountManager createManager(Context context) { + return new TextSecureAccountManager(Release.PUSH_URL, + new TextSecurePushTrustStore(context), + TextSecurePreferences.getLocalNumber(context), + TextSecurePreferences.getPushServerPassword(context)); + } + + public static TextSecureAccountManager createManager(Context context, String number, String password) { + return new TextSecureAccountManager(Release.PUSH_URL, new TextSecurePushTrustStore(context), + number, password); + } + private static class SecurityEventListener implements EventListener { private final Context context; diff --git a/src/org/thoughtcrime/securesms/push/TextSecureMessageReceiverFactory.java b/src/org/thoughtcrime/securesms/push/TextSecureMessageReceiverFactory.java deleted file mode 100644 index 73a20fb941..0000000000 --- a/src/org/thoughtcrime/securesms/push/TextSecureMessageReceiverFactory.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.thoughtcrime.securesms.push; - -import android.content.Context; - -import org.thoughtcrime.securesms.Release; -import org.thoughtcrime.securesms.crypto.MasterSecret; -import org.thoughtcrime.securesms.crypto.storage.TextSecureAxolotlStore; -import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.whispersystems.textsecure.api.TextSecureMessageReceiver; - -public class TextSecureMessageReceiverFactory { - public static TextSecureMessageReceiver create(Context context, MasterSecret masterSecret) { - return new TextSecureMessageReceiver(context, - TextSecurePreferences.getSignalingKey(context), - Release.PUSH_URL, - new TextSecurePushTrustStore(context), - TextSecurePreferences.getLocalNumber(context), - TextSecurePreferences.getPushServerPassword(context), - new TextSecureAxolotlStore(context, masterSecret)); - } -} diff --git a/src/org/thoughtcrime/securesms/service/DirectoryRefreshService.java b/src/org/thoughtcrime/securesms/service/DirectoryRefreshService.java index d6f50a591d..2c5b4a899a 100644 --- a/src/org/thoughtcrime/securesms/service/DirectoryRefreshService.java +++ b/src/org/thoughtcrime/securesms/service/DirectoryRefreshService.java @@ -7,7 +7,6 @@ import android.os.IBinder; import android.os.PowerManager; import android.util.Log; -import org.thoughtcrime.securesms.push.PushServiceSocketFactory; import org.thoughtcrime.securesms.util.DirectoryHelper; import java.util.concurrent.Executor; diff --git a/src/org/thoughtcrime/securesms/service/GcmRegistrationService.java b/src/org/thoughtcrime/securesms/service/GcmRegistrationService.java deleted file mode 100644 index 25e6a00616..0000000000 --- a/src/org/thoughtcrime/securesms/service/GcmRegistrationService.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.thoughtcrime.securesms.service; - -import android.app.Service; -import android.content.Intent; -import android.os.IBinder; -import android.util.Log; -import android.widget.Toast; - -import com.google.android.gms.common.ConnectionResult; -import com.google.android.gms.common.GooglePlayServicesUtil; -import com.google.android.gms.gcm.GoogleCloudMessaging; - -import org.thoughtcrime.securesms.R; -import org.thoughtcrime.securesms.push.PushServiceSocketFactory; -import org.thoughtcrime.securesms.util.Dialogs; -import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.whispersystems.textsecure.push.PushServiceSocket; - -import java.io.IOException; -import java.sql.Connection; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -public class GcmRegistrationService extends Service implements Runnable { - - private static final String TAG = GcmRegistrationService.class.getSimpleName(); - - public static final String REGISTRATION_ID = "312334754206"; - - private ExecutorService executor; - - @Override - public void onCreate() { - super.onCreate(); - this.executor = Executors.newSingleThreadExecutor(); - } - - @Override - public int onStartCommand(Intent intent, int flats, int startId) { - executor.execute(this); - return START_NOT_STICKY; - } - - @Override - public void run() { - Log.w(TAG, "Running GCM Registration Service..."); - try { - String registrationId = TextSecurePreferences.getGcmRegistrationId(this); - - if (registrationId == null) { - Log.w(TAG, "GCM registrationId expired, reregistering..."); - int result = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this); - - if (result != ConnectionResult.SUCCESS) { - Log.w(TAG, "Unable to register with GCM! " + result); - return; - } - - String gcmId = GoogleCloudMessaging.getInstance(this).register(REGISTRATION_ID); - PushServiceSocket socket = PushServiceSocketFactory.create(this); - - socket.registerGcmId(gcmId); - TextSecurePreferences.setGcmRegistrationId(this, gcmId); - - stopSelf(); - } - } catch (IOException e) { - Log.w(TAG, e); - } - } - - @Override - public void onDestroy() { - super.onDestroy(); - executor.shutdown(); - } - - @Override - public IBinder onBind(Intent intent) { - return null; - } - -} diff --git a/src/org/thoughtcrime/securesms/service/PreKeyService.java b/src/org/thoughtcrime/securesms/service/PreKeyService.java deleted file mode 100644 index 7a58a179bf..0000000000 --- a/src/org/thoughtcrime/securesms/service/PreKeyService.java +++ /dev/null @@ -1,230 +0,0 @@ -package org.thoughtcrime.securesms.service; - -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.os.IBinder; -import android.util.Log; - -import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; -import org.thoughtcrime.securesms.push.PushServiceSocketFactory; -import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.whispersystems.libaxolotl.IdentityKeyPair; -import org.whispersystems.libaxolotl.InvalidKeyIdException; -import org.whispersystems.libaxolotl.state.PreKeyRecord; -import org.whispersystems.libaxolotl.state.SignedPreKeyRecord; -import org.whispersystems.libaxolotl.state.SignedPreKeyStore; -import org.thoughtcrime.securesms.crypto.MasterSecret; -import org.thoughtcrime.securesms.crypto.PreKeyUtil; -import org.whispersystems.textsecure.push.PushServiceSocket; -import org.whispersystems.textsecure.push.SignedPreKeyEntity; -import org.thoughtcrime.securesms.crypto.storage.TextSecurePreKeyStore; - -import java.io.IOException; -import java.util.Arrays; -import java.util.Comparator; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; - -public class PreKeyService extends Service { - - private static final String TAG = PreKeyService.class.getSimpleName(); - public static final String REFRESH_ACTION = "org.thoughtcrime.securesms.PreKeyService.REFRESH"; - public static final String CLEAN_ACTION = "org.thoughtcrime.securesms.PreKeyService.CLEAN"; - public static final String CREATE_SIGNED_ACTION = "org.thoughtcrime.securesms.PreKeyService.CREATE_SIGNED"; - - private static final int PREKEY_MINIMUM = 10; - - private final Executor executor = Executors.newSingleThreadExecutor(); - - public static void initiateRefresh(Context context, MasterSecret masterSecret) { - Intent intent = new Intent(context, PreKeyService.class); - intent.setAction(PreKeyService.REFRESH_ACTION); - intent.putExtra("master_secret", masterSecret); - context.startService(intent); - } - - public static void initiateClean(Context context, MasterSecret masterSecret) { - Intent intent = new Intent(context, PreKeyService.class); - intent.setAction(PreKeyService.CLEAN_ACTION); - intent.putExtra("master_secret", masterSecret); - context.startService(intent); - } - - public static void initiateCreateSigned(Context context, MasterSecret masterSecret) { - Intent intent = new Intent(context, PreKeyService.class); - intent.setAction(PreKeyService.CREATE_SIGNED_ACTION); - intent.putExtra("master_secret", masterSecret); - context.startService(intent); - } - - @Override - public int onStartCommand(Intent intent, int flats, int startId) { - if (intent == null) return START_NOT_STICKY; - if (intent.getAction() == null) return START_NOT_STICKY; - - MasterSecret masterSecret = intent.getParcelableExtra("master_secret"); - - if (masterSecret == null) { - Log.w(TAG, "No master secret!"); - return START_NOT_STICKY; - } - - switch (intent.getAction()) { - case REFRESH_ACTION: executor.execute(new RefreshTask(this, masterSecret)); break; - case CLEAN_ACTION: executor.execute(new CleanSignedPreKeysTask(this, masterSecret)); break; - case CREATE_SIGNED_ACTION: executor.execute(new CreateSignedPreKeyTask(this, masterSecret)); break; - } - - return START_NOT_STICKY; - } - - @Override - public IBinder onBind(Intent intent) { - return null; - } - - private static class CreateSignedPreKeyTask implements Runnable { - - private final Context context; - private final MasterSecret masterSecret; - - public CreateSignedPreKeyTask(Context context, MasterSecret masterSecret) { - this.context = context; - this.masterSecret = masterSecret; - } - - @Override - public void run() { - if (TextSecurePreferences.isSignedPreKeyRegistered(context)) { - Log.w(TAG, "Signed prekey already registered..."); - return; - } - - try { - IdentityKeyPair identityKeyPair = IdentityKeyUtil.getIdentityKeyPair(context, masterSecret); - SignedPreKeyRecord signedPreKeyRecord = PreKeyUtil.generateSignedPreKey(context, masterSecret, identityKeyPair); - PushServiceSocket socket = PushServiceSocketFactory.create(context); - - socket.setCurrentSignedPreKey(signedPreKeyRecord); - TextSecurePreferences.setSignedPreKeyRegistered(context, true); - } catch (IOException e) { - Log.w(TAG, e); - } - } - } - - static class CleanSignedPreKeysTask implements Runnable { - - private final SignedPreKeyStore signedPreKeyStore; - private final PushServiceSocket socket; - - public CleanSignedPreKeysTask(Context context, MasterSecret masterSecret) { - this(new TextSecurePreKeyStore(context, masterSecret), PushServiceSocketFactory.create(context)); - } - - public CleanSignedPreKeysTask(SignedPreKeyStore signedPreKeyStore, PushServiceSocket socket) { - this.signedPreKeyStore = signedPreKeyStore; - this.socket = socket; - } - - public void run() { - try { - SignedPreKeyEntity currentSignedPreKey = socket.getCurrentSignedPreKey(); - - if (currentSignedPreKey == null) return; - - SignedPreKeyRecord currentRecord = signedPreKeyStore.loadSignedPreKey(currentSignedPreKey.getKeyId()); - List allRecords = signedPreKeyStore.loadSignedPreKeys(); - List oldRecords = removeCurrentRecord(allRecords, currentRecord); - SignedPreKeyRecord[] oldRecordsArray = oldRecords.toArray(new SignedPreKeyRecord[0]); - - Arrays.sort(oldRecordsArray, new SignedPreKeySorter()); - - Log.w(TAG, "Existing signed prekey record count: " + oldRecordsArray.length); - - if (oldRecordsArray.length > 3) { - long oldTimestamp = System.currentTimeMillis() - (14 * 24 * 60 * 60 * 1000); - SignedPreKeyRecord[] deletionCandidates = Arrays.copyOf(oldRecordsArray, oldRecordsArray.length - 1); - - for (SignedPreKeyRecord deletionCandidate : deletionCandidates) { - Log.w(TAG, "Old signed prekey record timestamp: " + deletionCandidate.getTimestamp()); - - if (deletionCandidate.getTimestamp() <= oldTimestamp) { - Log.w(TAG, "Remove signed prekey record: " + deletionCandidate.getId()); - signedPreKeyStore.removeSignedPreKey(deletionCandidate.getId()); - } - } - } - } catch (IOException | InvalidKeyIdException e) { - Log.w(TAG, e); - } - } - - private List removeCurrentRecord(List records, - SignedPreKeyRecord currentRecord) - { - List others = new LinkedList<>(); - - for (SignedPreKeyRecord record : records) { - if (record.getId() != currentRecord.getId()) { - others.add(record); - } - } - - return others; - } - } - - private static class RefreshTask implements Runnable { - - private final Context context; - private final MasterSecret masterSecret; - - public RefreshTask(Context context, MasterSecret masterSecret) { - this.context = context.getApplicationContext(); - this.masterSecret = masterSecret; - } - - public void run() { - try { - if (!TextSecurePreferences.isPushRegistered(context)) return; - - PushServiceSocket socket = PushServiceSocketFactory.create(context); - int availableKeys = socket.getAvailablePreKeys(); - - if (availableKeys >= PREKEY_MINIMUM && TextSecurePreferences.isSignedPreKeyRegistered(context)) { - Log.w(TAG, "Available keys sufficient: " + availableKeys); - return; - } - - List preKeyRecords = PreKeyUtil.generatePreKeys(context, masterSecret); - PreKeyRecord lastResortKeyRecord = PreKeyUtil.generateLastResortKey(context, masterSecret); - IdentityKeyPair identityKey = IdentityKeyUtil.getIdentityKeyPair(context, masterSecret); - SignedPreKeyRecord signedPreKeyRecord = PreKeyUtil.generateSignedPreKey(context, masterSecret, identityKey); - - Log.w(TAG, "Registering new prekeys..."); - - socket.registerPreKeys(identityKey.getPublicKey(), lastResortKeyRecord, - signedPreKeyRecord, preKeyRecords); - - TextSecurePreferences.setSignedPreKeyRegistered(context, true); - PreKeyService.initiateClean(context, masterSecret); - } catch (IOException e) { - Log.w(TAG, e); - } - } - } - - private static class SignedPreKeySorter implements Comparator { - @Override - public int compare(SignedPreKeyRecord lhs, SignedPreKeyRecord rhs) { - if (lhs.getTimestamp() < rhs.getTimestamp()) return -1; - else if (lhs.getTimestamp() > rhs.getTimestamp()) return 1; - else return 0; - } - } - -} diff --git a/src/org/thoughtcrime/securesms/service/RegistrationService.java b/src/org/thoughtcrime/securesms/service/RegistrationService.java index 56916edcdf..b48e29fd9c 100644 --- a/src/org/thoughtcrime/securesms/service/RegistrationService.java +++ b/src/org/thoughtcrime/securesms/service/RegistrationService.java @@ -14,17 +14,18 @@ import com.google.android.gms.gcm.GoogleCloudMessaging; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; -import org.thoughtcrime.securesms.push.PushServiceSocketFactory; +import org.thoughtcrime.securesms.crypto.MasterSecret; +import org.thoughtcrime.securesms.crypto.PreKeyUtil; +import org.thoughtcrime.securesms.push.TextSecureCommunicationFactory; import org.thoughtcrime.securesms.util.DirectoryHelper; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.libaxolotl.IdentityKeyPair; -import org.whispersystems.libaxolotl.state.SignedPreKeyRecord; import org.whispersystems.libaxolotl.state.PreKeyRecord; +import org.whispersystems.libaxolotl.state.SignedPreKeyRecord; import org.whispersystems.libaxolotl.util.KeyHelper; -import org.thoughtcrime.securesms.crypto.MasterSecret; -import org.thoughtcrime.securesms.crypto.PreKeyUtil; +import org.whispersystems.libaxolotl.util.guava.Optional; +import org.whispersystems.textsecure.api.TextSecureAccountManager; import org.whispersystems.textsecure.push.exceptions.ExpectationFailedException; -import org.whispersystems.textsecure.push.PushServiceSocket; import org.whispersystems.textsecure.util.Util; import java.io.IOException; @@ -153,9 +154,9 @@ public class RegistrationService extends Service { MasterSecret masterSecret = intent.getParcelableExtra("master_secret"); try { - PushServiceSocket socket = PushServiceSocketFactory.create(this, number, password); + TextSecureAccountManager accountManager = TextSecureCommunicationFactory.createManager(this, number, password); - handleCommonRegistration(masterSecret, socket, number); + handleCommonRegistration(masterSecret, accountManager, number); markAsVerified(number, password, signalingKey); @@ -191,14 +192,14 @@ public class RegistrationService extends Service { initializeChallengeListener(); setState(new RegistrationState(RegistrationState.STATE_CONNECTING, number)); - PushServiceSocket socket = PushServiceSocketFactory.create(this, number, password); - socket.createAccount(false); + TextSecureAccountManager accountManager = TextSecureCommunicationFactory.createManager(this, number, password); + accountManager.requestSmsVerificationCode(); setState(new RegistrationState(RegistrationState.STATE_VERIFYING, number)); String challenge = waitForChallenge(); - socket.verifyAccount(challenge, signalingKey, true, registrationId); + accountManager.verifyAccount(challenge, signalingKey, true, registrationId); - handleCommonRegistration(masterSecret, socket, number); + handleCommonRegistration(masterSecret, accountManager, number); markAsVerified(number, password, signalingKey); setState(new RegistrationState(RegistrationState.STATE_COMPLETE, number)); @@ -224,7 +225,7 @@ public class RegistrationService extends Service { } } - private void handleCommonRegistration(MasterSecret masterSecret, PushServiceSocket socket, String number) + private void handleCommonRegistration(MasterSecret masterSecret, TextSecureAccountManager accountManager, String number) throws IOException { setState(new RegistrationState(RegistrationState.STATE_GENERATING_KEYS, number)); @@ -232,15 +233,15 @@ public class RegistrationService extends Service { List records = PreKeyUtil.generatePreKeys(this, masterSecret); PreKeyRecord lastResort = PreKeyUtil.generateLastResortKey(this, masterSecret); SignedPreKeyRecord signedPreKey = PreKeyUtil.generateSignedPreKey(this, masterSecret, identityKey); - socket.registerPreKeys(identityKey.getPublicKey(), lastResort, signedPreKey, records); + accountManager.setPreKeys(identityKey.getPublicKey(),lastResort, signedPreKey, records); setState(new RegistrationState(RegistrationState.STATE_GCM_REGISTERING, number)); String gcmRegistrationId = GoogleCloudMessaging.getInstance(this).register("312334754206"); TextSecurePreferences.setGcmRegistrationId(this, gcmRegistrationId); - socket.registerGcmId(gcmRegistrationId); + accountManager.setGcmId(Optional.of(gcmRegistrationId)); - DirectoryHelper.refreshDirectory(this, socket, number); + DirectoryHelper.refreshDirectory(this, accountManager, number); DirectoryRefreshListener.schedule(this); } diff --git a/src/org/thoughtcrime/securesms/sms/MessageSender.java b/src/org/thoughtcrime/securesms/sms/MessageSender.java index a87d05b73d..adb4fdc08a 100644 --- a/src/org/thoughtcrime/securesms/sms/MessageSender.java +++ b/src/org/thoughtcrime/securesms/sms/MessageSender.java @@ -25,6 +25,8 @@ import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.EncryptingSmsDatabase; import org.thoughtcrime.securesms.database.MmsDatabase; +import org.thoughtcrime.securesms.database.NotInDirectoryException; +import org.thoughtcrime.securesms.database.TextSecureDirectory; import org.thoughtcrime.securesms.database.ThreadDatabase; import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.jobs.MmsSendJob; @@ -33,17 +35,16 @@ import org.thoughtcrime.securesms.jobs.PushMediaSendJob; import org.thoughtcrime.securesms.jobs.PushTextSendJob; import org.thoughtcrime.securesms.jobs.SmsSendJob; import org.thoughtcrime.securesms.mms.OutgoingMediaMessage; -import org.thoughtcrime.securesms.push.PushServiceSocketFactory; +import org.thoughtcrime.securesms.push.TextSecureCommunicationFactory; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipients; import org.thoughtcrime.securesms.util.GroupUtil; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.Util; import org.whispersystems.jobqueue.JobManager; -import org.whispersystems.textsecure.directory.Directory; -import org.whispersystems.textsecure.directory.NotInDirectoryException; +import org.whispersystems.libaxolotl.util.guava.Optional; +import org.whispersystems.textsecure.api.TextSecureAccountManager; import org.whispersystems.textsecure.push.ContactTokenDetails; -import org.whispersystems.textsecure.push.PushServiceSocket; import org.whispersystems.textsecure.util.DirectoryUtil; import org.whispersystems.textsecure.util.InvalidNumberException; @@ -263,24 +264,24 @@ public class MessageSender { } private static boolean isPushDestination(Context context, String destination) { - Directory directory = Directory.getInstance(context); + TextSecureDirectory directory = TextSecureDirectory.getInstance(context); try { return directory.isActiveNumber(destination); } catch (NotInDirectoryException e) { try { - PushServiceSocket socket = PushServiceSocketFactory.create(context); - String contactToken = DirectoryUtil.getDirectoryServerToken(destination); - ContactTokenDetails registeredUser = socket.getContactTokenDetails(contactToken); - - if (registeredUser == null) { - registeredUser = new ContactTokenDetails(); - registeredUser.setNumber(destination); - directory.setNumber(registeredUser, false); + TextSecureAccountManager accountManager = TextSecureCommunicationFactory.createManager(context); + String contactToken = DirectoryUtil.getDirectoryServerToken(destination); + Optional registeredUser = accountManager.getContact(contactToken); + + if (!registeredUser.isPresent()) { + registeredUser = Optional.of(new ContactTokenDetails()); + registeredUser.get().setNumber(destination); + directory.setNumber(registeredUser.get(), false); return false; } else { - registeredUser.setNumber(destination); - directory.setNumber(registeredUser, true); + registeredUser.get().setNumber(destination); + directory.setNumber(registeredUser.get(), true); return true; } } catch (IOException e1) { diff --git a/src/org/thoughtcrime/securesms/util/DirectoryHelper.java b/src/org/thoughtcrime/securesms/util/DirectoryHelper.java index 8238065131..e8b2004f66 100644 --- a/src/org/thoughtcrime/securesms/util/DirectoryHelper.java +++ b/src/org/thoughtcrime/securesms/util/DirectoryHelper.java @@ -5,13 +5,12 @@ import android.util.Log; import android.widget.Toast; import org.thoughtcrime.securesms.R; -import org.thoughtcrime.securesms.push.PushServiceSocketFactory; -import org.thoughtcrime.securesms.recipients.Recipient; +import org.thoughtcrime.securesms.database.NotInDirectoryException; +import org.thoughtcrime.securesms.database.TextSecureDirectory; +import org.thoughtcrime.securesms.push.TextSecureCommunicationFactory; import org.thoughtcrime.securesms.recipients.Recipients; -import org.whispersystems.textsecure.directory.Directory; -import org.whispersystems.textsecure.directory.NotInDirectoryException; +import org.whispersystems.textsecure.api.TextSecureAccountManager; import org.whispersystems.textsecure.push.ContactTokenDetails; -import org.whispersystems.textsecure.push.PushServiceSocket; import org.whispersystems.textsecure.util.DirectoryUtil; import org.whispersystems.textsecure.util.InvalidNumberException; @@ -54,19 +53,18 @@ public class DirectoryHelper { } public static void refreshDirectory(final Context context) { - refreshDirectory(context, PushServiceSocketFactory.create(context)); + refreshDirectory(context, TextSecureCommunicationFactory.createManager(context)); } - public static void refreshDirectory(final Context context, final PushServiceSocket socket) { - refreshDirectory(context, socket, TextSecurePreferences.getLocalNumber(context)); + public static void refreshDirectory(final Context context, final TextSecureAccountManager accountManager) { + refreshDirectory(context, accountManager, TextSecurePreferences.getLocalNumber(context)); } - public static void refreshDirectory(final Context context, final PushServiceSocket socket, final String localNumber) { - Directory directory = Directory.getInstance(context); + public static void refreshDirectory(final Context context, final TextSecureAccountManager accountManager, final String localNumber) { + TextSecureDirectory directory = TextSecureDirectory.getInstance(context); Set eligibleContactNumbers = directory.getPushEligibleContactNumbers(localNumber); Map tokenMap = DirectoryUtil.getDirectoryServerTokenMap(eligibleContactNumbers); - List activeTokens = socket.retrieveDirectory(tokenMap.keySet()); - + List activeTokens = accountManager.getContacts(tokenMap.keySet()); if (activeTokens != null) { for (ContactTokenDetails activeToken : activeTokens) { @@ -104,7 +102,7 @@ public class DirectoryHelper { final String e164number = Util.canonicalizeNumber(context, number); - return Directory.getInstance(context).isActiveNumber(e164number); + return TextSecureDirectory.getInstance(context).isActiveNumber(e164number); } catch (InvalidNumberException e) { Log.w(TAG, e); return false;