From 1ab4e7e9dedee03c3a0cf34a01bd690a3b564b0d Mon Sep 17 00:00:00 2001 From: Moxie Marlinspike Date: Wed, 27 Nov 2013 11:08:58 -0800 Subject: [PATCH] Library accepts push connection certificate as argument. --- .../textsecure/push/PushDestination.java | 4 +-- .../textsecure/push/PushServiceSocket.java | 30 ++++++++---------- res/raw/disclaimer | 5 --- {library/res => res}/raw/whisper.store | Bin .../ApplicationPreferencesActivity.java | 8 ++--- .../RegistrationProgressActivity.java | 5 +-- .../securesms/gcm/GcmIntentService.java | 6 ++-- .../push/PushServiceSocketFactory.java | 22 +++++++++++++ .../push/TextSecurePushTrustStore.java | 27 ++++++++++++++++ .../service/DirectoryRefreshService.java | 4 +-- .../securesms/service/PushDownloader.java | 4 +-- .../service/RegistrationService.java | 6 ++-- .../securesms/transport/PushTransport.java | 24 +++++++------- .../transport/UniversalTransport.java | 13 ++++---- .../util/TextSecurePushCredentials.java | 24 -------------- 15 files changed, 99 insertions(+), 83 deletions(-) delete mode 100644 res/raw/disclaimer rename {library/res => res}/raw/whisper.store (100%) create mode 100644 src/org/thoughtcrime/securesms/push/PushServiceSocketFactory.java create mode 100644 src/org/thoughtcrime/securesms/push/TextSecurePushTrustStore.java delete mode 100644 src/org/thoughtcrime/securesms/util/TextSecurePushCredentials.java diff --git a/library/src/org/whispersystems/textsecure/push/PushDestination.java b/library/src/org/whispersystems/textsecure/push/PushDestination.java index d844f53e7e..1126becc9b 100644 --- a/library/src/org/whispersystems/textsecure/push/PushDestination.java +++ b/library/src/org/whispersystems/textsecure/push/PushDestination.java @@ -25,11 +25,11 @@ public class PushDestination { } public static PushDestination create(Context context, - PushServiceSocket.PushCredentials credentials, + String localNumber, String destinationNumber) throws InvalidNumberException { - String e164destination = PhoneNumberFormatter.formatNumber(destinationNumber, credentials.getLocalNumber(context)); + String e164destination = PhoneNumberFormatter.formatNumber(destinationNumber, localNumber); String relay = Directory.getInstance(context).getRelay(e164destination); return new PushDestination(e164destination, relay); diff --git a/library/src/org/whispersystems/textsecure/push/PushServiceSocket.java b/library/src/org/whispersystems/textsecure/push/PushServiceSocket.java index b1e80d4d22..97442cc840 100644 --- a/library/src/org/whispersystems/textsecure/push/PushServiceSocket.java +++ b/library/src/org/whispersystems/textsecure/push/PushServiceSocket.java @@ -7,7 +7,6 @@ import android.util.Pair; import com.google.thoughtcrimegson.Gson; import org.apache.http.conn.ssl.StrictHostnameVerifier; -import org.whispersystems.textsecure.R; import org.whispersystems.textsecure.crypto.IdentityKey; import org.whispersystems.textsecure.storage.PreKeyRecord; import org.whispersystems.textsecure.util.Base64; @@ -57,16 +56,14 @@ public class PushServiceSocket { private final String password; private final TrustManagerFactory trustManagerFactory; - public PushServiceSocket(Context context, String serviceUrl, String localNumber, String password) { + public PushServiceSocket(Context context, String serviceUrl, TrustStore trustStore, + String localNumber, String password) + { this.context = context.getApplicationContext(); this.serviceUrl = serviceUrl; this.localNumber = localNumber; this.password = password; - this.trustManagerFactory = initializeTrustManagerFactory(context); - } - - public PushServiceSocket(Context context, String serviceUrl, PushCredentials credentials) { - this(context, serviceUrl, credentials.getLocalNumber(context), credentials.getPassword(context)); + this.trustManagerFactory = initializeTrustManagerFactory(trustStore); } public void createAccount(boolean voice) throws IOException { @@ -76,7 +73,8 @@ public class PushServiceSocket { public void verifyAccount(String verificationCode, String signalingKey) throws IOException { SignalingKey signalingKeyEntity = new SignalingKey(signalingKey); - makeRequest(String.format(VERIFY_ACCOUNT_PATH, verificationCode), "PUT", new Gson().toJson(signalingKeyEntity)); + makeRequest(String.format(VERIFY_ACCOUNT_PATH, verificationCode), + "PUT", new Gson().toJson(signalingKeyEntity)); } public void registerGcmId(String gcmRegistrationId) throws IOException { @@ -373,15 +371,15 @@ public class PushServiceSocket { } } - private TrustManagerFactory initializeTrustManagerFactory(Context context) { + private TrustManagerFactory initializeTrustManagerFactory(TrustStore trustStore) { try { - InputStream keyStoreInputStream = context.getResources().openRawResource(R.raw.whisper); - KeyStore trustStore = KeyStore.getInstance("BKS"); + InputStream keyStoreInputStream = trustStore.getKeyStoreInputStream(); + KeyStore keyStore = KeyStore.getInstance("BKS"); - trustStore.load(keyStoreInputStream, "whisper".toCharArray()); + keyStore.load(keyStoreInputStream, trustStore.getKeyStorePassword().toCharArray()); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509"); - trustManagerFactory.init(trustStore); + trustManagerFactory.init(keyStore); return trustManagerFactory; } catch (KeyStoreException kse) { @@ -417,8 +415,8 @@ public class PushServiceSocket { } } - public interface PushCredentials { - public String getLocalNumber(Context context); - public String getPassword(Context context); + public interface TrustStore { + public InputStream getKeyStoreInputStream(); + public String getKeyStorePassword(); } } diff --git a/res/raw/disclaimer b/res/raw/disclaimer deleted file mode 100644 index a9287d2276..0000000000 --- a/res/raw/disclaimer +++ /dev/null @@ -1,5 +0,0 @@ -Thank you for helping us test this BETA vesion of TextSecure. - -This is BETA software, please do not use it in situations where security is critical. - -Please report any problems at https://github.com/WhisperSystems/TextSecure/issues diff --git a/library/res/raw/whisper.store b/res/raw/whisper.store similarity index 100% rename from library/res/raw/whisper.store rename to res/raw/whisper.store diff --git a/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java b/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java index 1bcf9f2ae6..a5254caf4a 100644 --- a/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java +++ b/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java @@ -45,11 +45,11 @@ import android.widget.Toast; import com.actionbarsherlock.view.MenuItem; import com.google.android.gcm.GCMRegistrar; + import org.thoughtcrime.securesms.contacts.ContactAccessor; import org.thoughtcrime.securesms.contacts.ContactIdentityManager; -import org.thoughtcrime.securesms.util.TextSecurePushCredentials; -import org.whispersystems.textsecure.crypto.MasterSecret; import org.thoughtcrime.securesms.crypto.MasterSecretUtil; +import org.thoughtcrime.securesms.push.PushServiceSocketFactory; import org.thoughtcrime.securesms.service.KeyCachingService; import org.thoughtcrime.securesms.util.DynamicLanguage; import org.thoughtcrime.securesms.util.DynamicTheme; @@ -57,6 +57,7 @@ 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.whispersystems.textsecure.crypto.MasterSecret; import org.whispersystems.textsecure.push.AuthorizationFailedException; import org.whispersystems.textsecure.push.PushServiceSocket; @@ -307,8 +308,7 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredSherlockPr protected Integer doInBackground(Void... params) { try { Context context = ApplicationPreferencesActivity.this; - PushServiceSocket socket = new PushServiceSocket(context, Release.PUSH_URL, - TextSecurePushCredentials.getInstance()); + PushServiceSocket socket = PushServiceSocketFactory.create(context); socket.unregisterGcmId(); GCMRegistrar.unregister(context); diff --git a/src/org/thoughtcrime/securesms/RegistrationProgressActivity.java b/src/org/thoughtcrime/securesms/RegistrationProgressActivity.java index f3637c43c9..2a51044ff8 100644 --- a/src/org/thoughtcrime/securesms/RegistrationProgressActivity.java +++ b/src/org/thoughtcrime/securesms/RegistrationProgressActivity.java @@ -30,6 +30,7 @@ import android.widget.Toast; import com.actionbarsherlock.app.SherlockActivity; +import org.thoughtcrime.securesms.push.PushServiceSocketFactory; import org.thoughtcrime.securesms.service.RegistrationService; import org.whispersystems.textsecure.crypto.MasterSecret; import org.whispersystems.textsecure.push.PushServiceSocket; @@ -498,7 +499,7 @@ public class RegistrationProgressActivity extends SherlockActivity { @Override protected Integer doInBackground(Void... params) { try { - PushServiceSocket socket = new PushServiceSocket(context, Release.PUSH_URL, e164number, password); + PushServiceSocket socket = PushServiceSocketFactory.create(context, e164number, password); socket.verifyAccount(code, signalingKey); return SUCCESS; } catch (RateLimitException e) { @@ -585,7 +586,7 @@ public class RegistrationProgressActivity extends SherlockActivity { @Override protected Integer doInBackground(Void... params) { try { - PushServiceSocket socket = new PushServiceSocket(context, Release.PUSH_URL, e164number, password); + PushServiceSocket socket = PushServiceSocketFactory.create(context, e164number, password); socket.createAccount(true); return SUCCESS; diff --git a/src/org/thoughtcrime/securesms/gcm/GcmIntentService.java b/src/org/thoughtcrime/securesms/gcm/GcmIntentService.java index bb4e88659d..859ba5ee98 100644 --- a/src/org/thoughtcrime/securesms/gcm/GcmIntentService.java +++ b/src/org/thoughtcrime/securesms/gcm/GcmIntentService.java @@ -7,10 +7,10 @@ import android.util.Log; import com.google.android.gcm.GCMBaseIntentService; import org.thoughtcrime.securesms.Release; +import org.thoughtcrime.securesms.push.PushServiceSocketFactory; import org.thoughtcrime.securesms.service.RegistrationService; import org.thoughtcrime.securesms.service.SendReceiveService; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.thoughtcrime.securesms.util.TextSecurePushCredentials; import org.whispersystems.textsecure.crypto.InvalidVersionException; import org.whispersystems.textsecure.directory.Directory; import org.whispersystems.textsecure.directory.NotInDirectoryException; @@ -34,7 +34,7 @@ public class GcmIntentService extends GCMBaseIntentService { sendBroadcast(intent); } else { try { - PushServiceSocket pushSocket = new PushServiceSocket(context, Release.PUSH_URL, TextSecurePushCredentials.getInstance()); + PushServiceSocket pushSocket = PushServiceSocketFactory.create(context); pushSocket.registerGcmId(registrationId); } catch (IOException e) { Log.w("GcmIntentService", e); @@ -45,7 +45,7 @@ public class GcmIntentService extends GCMBaseIntentService { @Override protected void onUnregistered(Context context, String registrationId) { try { - PushServiceSocket pushSocket = new PushServiceSocket(context, Release.PUSH_URL, TextSecurePushCredentials.getInstance()); + PushServiceSocket pushSocket = PushServiceSocketFactory.create(context); pushSocket.unregisterGcmId(); } catch (IOException ioe) { Log.w("GcmIntentService", ioe); diff --git a/src/org/thoughtcrime/securesms/push/PushServiceSocketFactory.java b/src/org/thoughtcrime/securesms/push/PushServiceSocketFactory.java new file mode 100644 index 0000000000..07db068e5e --- /dev/null +++ b/src/org/thoughtcrime/securesms/push/PushServiceSocketFactory.java @@ -0,0 +1,22 @@ +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/TextSecurePushTrustStore.java b/src/org/thoughtcrime/securesms/push/TextSecurePushTrustStore.java new file mode 100644 index 0000000000..a1333bdedd --- /dev/null +++ b/src/org/thoughtcrime/securesms/push/TextSecurePushTrustStore.java @@ -0,0 +1,27 @@ +package org.thoughtcrime.securesms.push; + +import android.content.Context; + +import org.thoughtcrime.securesms.R; +import org.whispersystems.textsecure.push.PushServiceSocket; + +import java.io.InputStream; + +public class TextSecurePushTrustStore implements PushServiceSocket.TrustStore { + + private final Context context; + + public TextSecurePushTrustStore(Context context) { + this.context = context.getApplicationContext(); + } + + @Override + public InputStream getKeyStoreInputStream() { + return context.getResources().openRawResource(R.raw.whisper); + } + + @Override + public String getKeyStorePassword() { + return "whisper"; + } +} diff --git a/src/org/thoughtcrime/securesms/service/DirectoryRefreshService.java b/src/org/thoughtcrime/securesms/service/DirectoryRefreshService.java index e9b70b6bee..a815b41111 100644 --- a/src/org/thoughtcrime/securesms/service/DirectoryRefreshService.java +++ b/src/org/thoughtcrime/securesms/service/DirectoryRefreshService.java @@ -8,8 +8,8 @@ import android.os.PowerManager; import android.util.Log; import org.thoughtcrime.securesms.Release; +import org.thoughtcrime.securesms.push.PushServiceSocketFactory; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.thoughtcrime.securesms.util.TextSecurePushCredentials; import org.whispersystems.textsecure.directory.Directory; import org.whispersystems.textsecure.push.ContactTokenDetails; @@ -60,7 +60,7 @@ public class DirectoryRefreshService extends Service { try { Log.w("DirectoryRefreshService", "Refreshing directory..."); Directory directory = Directory.getInstance(context); - PushServiceSocket socket = new PushServiceSocket(context, Release.PUSH_URL, TextSecurePushCredentials.getInstance()); + PushServiceSocket socket = PushServiceSocketFactory.create(context); Set eligibleContactTokens = directory.getPushEligibleContactTokens(TextSecurePreferences.getLocalNumber(context)); List activeTokens = socket.retrieveDirectory(eligibleContactTokens); diff --git a/src/org/thoughtcrime/securesms/service/PushDownloader.java b/src/org/thoughtcrime/securesms/service/PushDownloader.java index 32ff719fd7..7ae620b772 100644 --- a/src/org/thoughtcrime/securesms/service/PushDownloader.java +++ b/src/org/thoughtcrime/securesms/service/PushDownloader.java @@ -10,7 +10,7 @@ import org.thoughtcrime.securesms.Release; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.EncryptingPartDatabase; import org.thoughtcrime.securesms.database.PartDatabase; -import org.thoughtcrime.securesms.util.TextSecurePushCredentials; +import org.thoughtcrime.securesms.push.PushServiceSocketFactory; import org.thoughtcrime.securesms.util.Util; import org.whispersystems.textsecure.crypto.AttachmentCipherInputStream; import org.whispersystems.textsecure.crypto.InvalidMessageException; @@ -111,7 +111,7 @@ public class PushDownloader { } private File downloadAttachment(String relay, long contentLocation) throws IOException { - PushServiceSocket socket = new PushServiceSocket(context, Release.PUSH_URL, TextSecurePushCredentials.getInstance()); + PushServiceSocket socket = PushServiceSocketFactory.create(context); return socket.retrieveAttachment(relay, contentLocation); } diff --git a/src/org/thoughtcrime/securesms/service/RegistrationService.java b/src/org/thoughtcrime/securesms/service/RegistrationService.java index b6e7653e17..ad4a0b5bbc 100644 --- a/src/org/thoughtcrime/securesms/service/RegistrationService.java +++ b/src/org/thoughtcrime/securesms/service/RegistrationService.java @@ -13,10 +13,10 @@ import android.util.Log; import com.google.android.gcm.GCMRegistrar; import org.thoughtcrime.securesms.R; -import org.thoughtcrime.securesms.Release; import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; import org.thoughtcrime.securesms.gcm.GcmIntentService; import org.thoughtcrime.securesms.gcm.GcmRegistrationTimeoutException; +import org.thoughtcrime.securesms.push.PushServiceSocketFactory; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.textsecure.crypto.IdentityKey; import org.whispersystems.textsecure.crypto.MasterSecret; @@ -198,7 +198,7 @@ public class RegistrationService extends Service { initializeGcmRegistrationListener(); initializePreKeyGenerator(masterSecret); - PushServiceSocket socket = new PushServiceSocket(this, Release.PUSH_URL, number, password); + PushServiceSocket socket = PushServiceSocketFactory.create(this, number, password); handleCommonRegistration(masterSecret, socket, number); @@ -238,7 +238,7 @@ public class RegistrationService extends Service { initializePreKeyGenerator(masterSecret); setState(new RegistrationState(RegistrationState.STATE_CONNECTING, number)); - PushServiceSocket socket = new PushServiceSocket(this, Release.PUSH_URL, number, password); + PushServiceSocket socket = PushServiceSocketFactory.create(this, number, password); socket.createAccount(false); setState(new RegistrationState(RegistrationState.STATE_VERIFYING, number)); diff --git a/src/org/thoughtcrime/securesms/transport/PushTransport.java b/src/org/thoughtcrime/securesms/transport/PushTransport.java index 4053d01f95..4d7ae61a49 100644 --- a/src/org/thoughtcrime/securesms/transport/PushTransport.java +++ b/src/org/thoughtcrime/securesms/transport/PushTransport.java @@ -22,16 +22,15 @@ import android.util.Log; import com.google.protobuf.ByteString; -import org.thoughtcrime.securesms.Release; -import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; import org.thoughtcrime.securesms.crypto.KeyExchangeProcessorV2; import org.thoughtcrime.securesms.database.model.SmsMessageRecord; import org.thoughtcrime.securesms.mms.PartParser; +import org.thoughtcrime.securesms.push.PushServiceSocketFactory; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientFactory; import org.thoughtcrime.securesms.recipients.RecipientFormattingException; import org.thoughtcrime.securesms.recipients.Recipients; -import org.thoughtcrime.securesms.util.TextSecurePushCredentials; +import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.Util; import org.whispersystems.textsecure.crypto.AttachmentCipher; import org.whispersystems.textsecure.crypto.InvalidKeyException; @@ -70,12 +69,12 @@ public class PushTransport extends BaseTransport { public void deliver(SmsMessageRecord message) throws IOException { try { - TextSecurePushCredentials credentials = TextSecurePushCredentials.getInstance(); - Recipient recipient = message.getIndividualRecipient(); - long threadId = message.getThreadId(); - PushServiceSocket socket = new PushServiceSocket(context, Release.PUSH_URL, credentials); - PushDestination destination = PushDestination.create(context, credentials, - recipient.getNumber()); + String localNumber = TextSecurePreferences.getLocalNumber(context); + Recipient recipient = message.getIndividualRecipient(); + long threadId = message.getThreadId(); + PushServiceSocket socket = PushServiceSocketFactory.create(context); + PushDestination destination = PushDestination.create(context, localNumber, + recipient.getNumber()); String plaintextBody = message.getBody().getBody(); byte[] plaintext = PushMessageContent.newBuilder().setBody(plaintextBody).build().toByteArray(); @@ -97,10 +96,9 @@ public class PushTransport extends BaseTransport { throws IOException { try { - TextSecurePushCredentials credentials = TextSecurePushCredentials.getInstance(); - PushServiceSocket socket = new PushServiceSocket(context, Release.PUSH_URL, credentials); - String messageBody = PartParser.getMessageText(message.getBody()); - List pushBodies = new LinkedList(); + PushServiceSocket socket = PushServiceSocketFactory.create(context); + String messageBody = PartParser.getMessageText(message.getBody()); + List pushBodies = new LinkedList(); for (PushDestination destination : destinations) { Recipients recipients = RecipientFactory.getRecipientsFromString(context, destination.getNumber(), false); diff --git a/src/org/thoughtcrime/securesms/transport/UniversalTransport.java b/src/org/thoughtcrime/securesms/transport/UniversalTransport.java index 00724ed337..923517141d 100644 --- a/src/org/thoughtcrime/securesms/transport/UniversalTransport.java +++ b/src/org/thoughtcrime/securesms/transport/UniversalTransport.java @@ -19,12 +19,11 @@ package org.thoughtcrime.securesms.transport; import android.content.Context; import android.util.Log; -import org.thoughtcrime.securesms.Release; import org.thoughtcrime.securesms.database.model.SmsMessageRecord; import org.thoughtcrime.securesms.mms.MmsSendResult; +import org.thoughtcrime.securesms.push.PushServiceSocketFactory; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.thoughtcrime.securesms.util.TextSecurePushCredentials; import org.thoughtcrime.securesms.util.Util; import org.whispersystems.textsecure.crypto.MasterSecret; import org.whispersystems.textsecure.directory.Directory; @@ -115,24 +114,24 @@ public class UniversalTransport { private List getMediaDestinations(SendReq mediaMessage) throws InvalidNumberException { - TextSecurePushCredentials credentials = TextSecurePushCredentials.getInstance(); + String localNumber = TextSecurePreferences.getLocalNumber(context); LinkedList destinations = new LinkedList(); if (mediaMessage.getTo() != null) { for (EncodedStringValue to : mediaMessage.getTo()) { - destinations.add(PushDestination.create(context, credentials, to.getString())); + destinations.add(PushDestination.create(context, localNumber, to.getString())); } } if (mediaMessage.getCc() != null) { for (EncodedStringValue cc : mediaMessage.getCc()) { - destinations.add(PushDestination.create(context, credentials, cc.getString())); + destinations.add(PushDestination.create(context, localNumber, cc.getString())); } } if (mediaMessage.getBcc() != null) { for (EncodedStringValue bcc : mediaMessage.getBcc()) { - destinations.add(PushDestination.create(context, credentials, bcc.getString())); + destinations.add(PushDestination.create(context, localNumber, bcc.getString())); } } @@ -146,7 +145,7 @@ public class UniversalTransport { return directory.isActiveNumber(destination); } catch (NotInDirectoryException e) { try { - PushServiceSocket socket = new PushServiceSocket(context, Release.PUSH_URL, TextSecurePushCredentials.getInstance()); + PushServiceSocket socket = PushServiceSocketFactory.create(context); String contactToken = directory.getToken(destination); ContactTokenDetails registeredUser = socket.getContactTokenDetails(contactToken); diff --git a/src/org/thoughtcrime/securesms/util/TextSecurePushCredentials.java b/src/org/thoughtcrime/securesms/util/TextSecurePushCredentials.java deleted file mode 100644 index c4adfb51c2..0000000000 --- a/src/org/thoughtcrime/securesms/util/TextSecurePushCredentials.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.thoughtcrime.securesms.util; - -import android.content.Context; - -import org.whispersystems.textsecure.push.PushServiceSocket; - -public class TextSecurePushCredentials implements PushServiceSocket.PushCredentials { - - private static final TextSecurePushCredentials instance = new TextSecurePushCredentials(); - - public static TextSecurePushCredentials getInstance() { - return instance; - } - - @Override - public String getLocalNumber(Context context) { - return TextSecurePreferences.getLocalNumber(context); - } - - @Override - public String getPassword(Context context) { - return TextSecurePreferences.getPushServerPassword(context); - } -}