Skip to content

Commit

Permalink
Consolidate S3 requests into one interface.
Browse files Browse the repository at this point in the history
  • Loading branch information
cody-signal authored and alex-signal committed May 12, 2022
1 parent bb963f9 commit ecc358e
Show file tree
Hide file tree
Showing 10 changed files with 109 additions and 177 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.payments.Payments;
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
import org.thoughtcrime.securesms.push.SignalServiceTrustStore;
import org.thoughtcrime.securesms.recipients.LiveRecipientCache;
import org.thoughtcrime.securesms.revealable.ViewOnceMessageManager;
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
Expand All @@ -50,8 +51,20 @@
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
import org.whispersystems.signalservice.api.SignalWebSocket;
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
import org.whispersystems.signalservice.api.push.TrustStore;
import org.whispersystems.signalservice.api.services.DonationsService;
import org.whispersystems.signalservice.api.util.Tls12SocketFactory;
import org.whispersystems.signalservice.internal.util.BlacklistingTrustManager;
import org.whispersystems.signalservice.internal.util.Util;

import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import okhttp3.ConnectionSpec;
import okhttp3.OkHttpClient;

/**
Expand Down Expand Up @@ -97,6 +110,7 @@ public class ApplicationDependencies {
private static volatile SignalCallManager signalCallManager;
private static volatile ShakeToReport shakeToReport;
private static volatile OkHttpClient okHttpClient;
private static volatile OkHttpClient signalOkHttpClient;
private static volatile PendingRetryReceiptManager pendingRetryReceiptManager;
private static volatile PendingRetryReceiptCache pendingRetryReceiptCache;
private static volatile SignalWebSocket signalWebSocket;
Expand Down Expand Up @@ -509,6 +523,32 @@ public static TypingStatusSender getTypingStatusSender() {
return okHttpClient;
}

public static @NonNull OkHttpClient getSignalOkHttpClient() {
if (signalOkHttpClient == null) {
synchronized (LOCK) {
if (signalOkHttpClient == null) {
try {
OkHttpClient baseClient = ApplicationDependencies.getOkHttpClient();
SSLContext sslContext = SSLContext.getInstance("TLS");
TrustStore trustStore = new SignalServiceTrustStore(ApplicationDependencies.getApplication());
TrustManager[] trustManagers = BlacklistingTrustManager.createFor(trustStore);

sslContext.init(null, trustManagers, null);

signalOkHttpClient = baseClient.newBuilder()
.sslSocketFactory(new Tls12SocketFactory(sslContext.getSocketFactory()), (X509TrustManager) trustManagers[0])
.connectionSpecs(Util.immutableList(ConnectionSpec.RESTRICTED_TLS))
.build();
} catch (NoSuchAlgorithmException | KeyManagementException e) {
throw new AssertionError(e);
}
}
}
}

return signalOkHttpClient;
}

public static @NonNull AppForegroundObserver getAppForegroundObserver() {
return appForegroundObserver;
}
Expand Down
61 changes: 10 additions & 51 deletions app/src/main/java/org/thoughtcrime/securesms/emoji/EmojiRemote.kt
Original file line number Diff line number Diff line change
@@ -1,88 +1,47 @@
package org.thoughtcrime.securesms.emoji

import okhttp3.Request
import okhttp3.Response
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.s3.S3
import java.io.IOException

private const val VERSION_URL = "https://updates.signal.org/dynamic/android/emoji/version_v3.txt"
private const val BASE_STATIC_BUCKET_URL = "https://updates.signal.org/static/android/emoji"
private const val BASE_STATIC_BUCKET_URI = "${S3.STATIC_PATH}/android/emoji"

/**
* Responsible for communicating with S3 to download Emoji related objects.
*/
object EmojiRemote {

private const val TAG = "EmojiRemote"

private val okHttpClient = ApplicationDependencies.getOkHttpClient()
private const val VERSION_URI = "${S3.DYNAMIC_PATH}/android/emoji/version_v3.txt"

@JvmStatic
@Throws(IOException::class)
fun getVersion(): Int {
val request = Request.Builder()
.get()
.url(VERSION_URL)
.build()

try {
okHttpClient.newCall(request).execute().use { response ->
if (!response.isSuccessful) {
throw IOException()
}

return response.body()?.bytes()?.let { String(it).trim().toIntOrNull() } ?: throw IOException()
}
} catch (e: IOException) {
throw e
}
return S3.getLong(VERSION_URI).toInt()
}

/**
* Downloads and returns the MD5 hash stored in an S3 object's ETag
*/
@JvmStatic
fun getMd5(emojiRequest: EmojiRequest): ByteArray? {
val request = Request.Builder()
.head()
.url(emojiRequest.url)
.build()

try {
okHttpClient.newCall(request).execute().use { response ->
if (!response.isSuccessful) {
throw IOException()
}

return response.header("ETag")?.toByteArray()
}
} catch (e: IOException) {
Log.w(TAG, "Could not retrieve md5", e)
return null
}
return S3.getObjectMD5(emojiRequest.uri)
}

/**
* Downloads an object for the specified name.
*/
@JvmStatic
fun getObject(emojiRequest: EmojiRequest): Response {
val request = Request.Builder()
.get()
.url(emojiRequest.url)
.build()

return okHttpClient.newCall(request).execute()
return S3.getObject(emojiRequest.uri)
}
}

interface EmojiRequest {
val url: String
val uri: String
}

class EmojiJsonRequest(version: Int) : EmojiRequest {
override val url: String = "$BASE_STATIC_BUCKET_URL/$version/emoji_data.json"
override val uri: String = "$BASE_STATIC_BUCKET_URI/$version/emoji_data.json"
}

class EmojiImageRequest(
Expand All @@ -91,13 +50,13 @@ class EmojiImageRequest(
name: String,
format: String
) : EmojiRequest {
override val url: String = "$BASE_STATIC_BUCKET_URL/$version/$density/$name.$format"
override val uri: String = "$BASE_STATIC_BUCKET_URI/$version/$density/$name.$format"
}

class EmojiFileRequest(
version: Int,
density: String,
name: String,
) : EmojiRequest {
override val url: String = "$BASE_STATIC_BUCKET_URL/$version/$density/$name"
override val uri: String = "$BASE_STATIC_BUCKET_URI/$version/$density/$name"
}
10 changes: 5 additions & 5 deletions app/src/main/java/org/thoughtcrime/securesms/fonts/Fonts.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ object Fonts {

private val TAG = Log.tag(Fonts::class.java)

private const val VERSION_URL = "https://updates.signal.org/dynamic/story-fonts/version.txt"
private const val BASE_STATIC_BUCKET_URL = "https://updates.signal.org/static/story-fonts"
private const val VERSION_URI = "${S3.DYNAMIC_PATH}/story-fonts/version.txt"
private const val BASE_STATIC_BUCKET_URI = "${S3.STATIC_PATH}/story-fonts"
private const val MANIFEST = "manifest.json"

private val taskCache = Collections.synchronizedMap(mutableMapOf<FontDownloadKey, ListenableFutureTask<Typeface>>())
Expand Down Expand Up @@ -201,7 +201,7 @@ object Fonts {
*/
@WorkerThread
fun downloadLatestVersionLong(): Long {
return S3.getLong(VERSION_URL)
return S3.getLong(VERSION_URI)
}

/**
Expand All @@ -211,7 +211,7 @@ object Fonts {
fun downloadAndVerifyLatestManifest(context: Context, version: FontVersion, manifestPath: String): Boolean {
return S3.verifyAndWriteToDisk(
context,
"$BASE_STATIC_BUCKET_URL/${version.id}/$MANIFEST",
"$BASE_STATIC_BUCKET_URI/${version.id}/$MANIFEST",
File(getDirectory(context), manifestPath)
)
}
Expand All @@ -227,7 +227,7 @@ object Fonts {

val script: FontManifest.FontScript = resolveFontScriptFromScriptName(supportedScript, fontManifest) ?: return null
val path = getScriptPath(font, script) ?: return null
val networkPath = "$BASE_STATIC_BUCKET_URL/${fontVersion.id}/$path"
val networkPath = "$BASE_STATIC_BUCKET_URI/${fontVersion.id}/$path"
val localUUID = UUID.randomUUID().toString()
val localPath = "${fontVersion.path}/" + localUUID

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,9 @@

import org.thoughtcrime.securesms.badges.models.Badge;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.push.SignalServiceTrustStore;
import org.whispersystems.signalservice.api.push.TrustStore;
import org.whispersystems.signalservice.api.util.Tls12SocketFactory;
import org.whispersystems.signalservice.internal.util.BlacklistingTrustManager;
import org.whispersystems.signalservice.internal.util.Util;

import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import okhttp3.ConnectionSpec;
import okhttp3.OkHttpClient;

/**
Expand All @@ -50,23 +38,7 @@ public boolean handles(@NonNull Badge badgeSpriteSheetRequest) {
}

public static Factory createFactory() {
try {
OkHttpClient baseClient = ApplicationDependencies.getOkHttpClient();
SSLContext sslContext = SSLContext.getInstance("TLS");
TrustStore trustStore = new SignalServiceTrustStore(ApplicationDependencies.getApplication());
TrustManager[] trustManagers = BlacklistingTrustManager.createFor(trustStore);

sslContext.init(null, trustManagers, null);

OkHttpClient client = baseClient.newBuilder()
.sslSocketFactory(new Tls12SocketFactory(sslContext.getSocketFactory()), (X509TrustManager) trustManagers[0])
.connectionSpecs(Util.immutableList(ConnectionSpec.RESTRICTED_TLS))
.build();

return new Factory(client);
} catch (NoSuchAlgorithmException | KeyManagementException e) {
throw new AssertionError(e);
}
return new Factory(ApplicationDependencies.getSignalOkHttpClient());
}

public static class Factory implements ModelLoaderFactory<Badge, InputStream> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,15 @@ import com.bumptech.glide.load.model.GlideUrl
import com.bumptech.glide.load.model.ModelLoader
import com.bumptech.glide.load.model.ModelLoaderFactory
import com.bumptech.glide.load.model.MultiModelLoaderFactory
import okhttp3.ConnectionSpec
import okhttp3.OkHttpClient
import org.signal.libsignal.zkgroup.receipts.ReceiptCredentialPresentation
import org.thoughtcrime.securesms.badges.Badges
import org.thoughtcrime.securesms.database.model.databaseprotos.GiftBadge
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.push.SignalServiceTrustStore
import org.whispersystems.signalservice.api.push.TrustStore
import org.whispersystems.signalservice.api.util.Tls12SocketFactory
import org.whispersystems.signalservice.internal.util.BlacklistingTrustManager
import org.whispersystems.signalservice.internal.util.Util
import java.io.InputStream
import java.lang.Exception
import java.security.KeyManagementException
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException
import java.util.Locale
import javax.net.ssl.SSLContext
import javax.net.ssl.X509TrustManager

/**
* Glide Model allowing the direct loading of a GiftBadge.
Expand Down Expand Up @@ -102,25 +92,7 @@ data class GiftBadgeModel(val giftBadge: GiftBadge) : Key {
companion object {
@JvmStatic
fun createFactory(): Factory {
return try {
val baseClient = ApplicationDependencies.getOkHttpClient()
val sslContext = SSLContext.getInstance("TLS")
val trustStore: TrustStore = SignalServiceTrustStore(ApplicationDependencies.getApplication())
val trustManagers = BlacklistingTrustManager.createFor(trustStore)

sslContext.init(null, trustManagers, null)

val client = baseClient.newBuilder()
.sslSocketFactory(Tls12SocketFactory(sslContext.socketFactory), trustManagers[0] as X509TrustManager)
.connectionSpecs(Util.immutableList(ConnectionSpec.RESTRICTED_TLS))
.build()

Factory(client)
} catch (e: NoSuchAlgorithmException) {
throw AssertionError(e)
} catch (e: KeyManagementException) {
throw AssertionError(e)
}
return Factory(ApplicationDependencies.getSignalOkHttpClient())
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import androidx.annotation.VisibleForTesting;

import org.greenrobot.eventbus.EventBus;
import org.signal.core.util.Hex;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.protocol.InvalidMessageException;
import org.thoughtcrime.securesms.attachments.Attachment;
Expand All @@ -23,10 +24,10 @@
import org.thoughtcrime.securesms.mms.MmsException;
import org.thoughtcrime.securesms.notifications.v2.NotificationThread;
import org.thoughtcrime.securesms.releasechannel.ReleaseChannel;
import org.thoughtcrime.securesms.s3.S3;
import org.thoughtcrime.securesms.transport.RetryLaterException;
import org.thoughtcrime.securesms.util.AttachmentUtil;
import org.thoughtcrime.securesms.util.Base64;
import org.signal.core.util.Hex;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer;
Expand All @@ -43,7 +44,6 @@
import java.util.Optional;
import java.util.concurrent.TimeUnit;

import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Okio;
Expand Down Expand Up @@ -242,12 +242,7 @@ private void retrieveUrlAttachment(long messageId,
final Attachment attachment)
throws IOException
{
Request request = new Request.Builder()
.get()
.url(Objects.requireNonNull(attachment.getFileName()))
.build();

try (Response response = ApplicationDependencies.getOkHttpClient().newCall(request).execute()) {
try (Response response = S3.getObject(Objects.requireNonNull(attachment.getFileName()))) {
ResponseBody body = response.body();
if (body != null) {
SignalDatabase.attachments().insertAttachmentsForPlaceholder(messageId, attachmentId, Okio.buffer(body.source()).inputStream());
Expand Down
Loading

0 comments on commit ecc358e

Please sign in to comment.