Skip to content

Commit e075acd

Browse files
committed
Defer attachment secret access until it's actually needed
1 parent 960bde8 commit e075acd

File tree

10 files changed

+71
-59
lines changed

10 files changed

+71
-59
lines changed

app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ import androidx.recyclerview.widget.RecyclerView
5959
import com.annimon.stream.Stream
6060
import com.bumptech.glide.Glide
6161
import com.squareup.phrase.Phrase
62+
import dagger.Lazy
6263
import dagger.hilt.android.AndroidEntryPoint
6364
import dagger.hilt.android.lifecycle.withCreationCallback
6465
import kotlinx.coroutines.CancellationException
@@ -263,7 +264,6 @@ class ConversationActivityV2 : ScreenLockActionBarActivity(), InputBarDelegate,
263264
@Inject lateinit var typingStatusRepository: TypingStatusRepository
264265
@Inject lateinit var typingStatusSender: TypingStatusSender
265266
@Inject lateinit var openGroupManager: OpenGroupManager
266-
@Inject lateinit var attachmentDatabase: AttachmentDatabase
267267
@Inject lateinit var clock: SnodeClock
268268
@Inject @ManagerScope
269269
lateinit var scope: CoroutineScope

app/src/main/java/org/thoughtcrime/securesms/database/AttachmentDatabase.java

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,16 @@
2626
import android.text.TextUtils;
2727
import android.util.Pair;
2828

29-
import androidx.annotation.NonNull;
30-
import androidx.annotation.Nullable;
3129
import androidx.annotation.VisibleForTesting;
3230

3331
import com.bumptech.glide.Glide;
3432

3533
import net.zetetic.database.sqlcipher.SQLiteDatabase;
3634

37-
import org.apache.commons.lang3.StringUtils;
3835
import org.json.JSONArray;
3936
import org.json.JSONException;
37+
import org.jspecify.annotations.NonNull;
38+
import org.jspecify.annotations.Nullable;
4039
import org.session.libsession.messaging.sending_receiving.attachments.Attachment;
4140
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentId;
4241
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentState;
@@ -80,14 +79,19 @@
8079
import java.util.concurrent.ExecutionException;
8180
import java.util.concurrent.ExecutorService;
8281

82+
import javax.inject.Inject;
8383
import javax.inject.Provider;
84+
import javax.inject.Singleton;
8485

86+
import dagger.Lazy;
87+
import dagger.hilt.android.qualifiers.ApplicationContext;
8588
import kotlin.jvm.Synchronized;
8689
import kotlinx.coroutines.channels.BufferOverflow;
8790
import kotlinx.coroutines.flow.MutableSharedFlow;
8891
import kotlinx.coroutines.flow.SharedFlow;
8992
import kotlinx.coroutines.flow.SharedFlowKt;
9093

94+
@Singleton
9195
public class AttachmentDatabase extends Database {
9296

9397
private static final String TAG = AttachmentDatabase.class.getSimpleName();
@@ -161,13 +165,18 @@ public class AttachmentDatabase extends Database {
161165

162166
final ExecutorService thumbnailExecutor = Util.newSingleThreadedLifoExecutor();
163167

164-
private final AttachmentSecret attachmentSecret;
168+
private final Lazy<@NonNull AttachmentSecret> attachmentSecret;
165169

166170
private final MutableSharedFlow<Object> mutableChangesNotification = SharedFlowKt.MutableSharedFlow(
167171
0, 100, BufferOverflow.DROP_OLDEST
168172
);
169173

170-
public AttachmentDatabase(Context context, Provider<SQLCipherOpenHelper> databaseHelper, AttachmentSecret attachmentSecret) {
174+
@Inject
175+
public AttachmentDatabase(
176+
@ApplicationContext Context context,
177+
Provider<SQLCipherOpenHelper> databaseHelper,
178+
Lazy<@NonNull AttachmentSecret> attachmentSecret
179+
) {
171180
super(context, databaseHelper);
172181
this.attachmentSecret = attachmentSecret;
173182
}
@@ -535,9 +544,9 @@ public void setTransferState(@NonNull AttachmentId attachmentId, int transferSta
535544

536545
try {
537546
if (dataInfo.random != null && dataInfo.random.length == 32) {
538-
return ModernDecryptingPartInputStream.createFor(attachmentSecret, dataInfo.random, dataInfo.file, offset);
547+
return ModernDecryptingPartInputStream.createFor(attachmentSecret.get(), dataInfo.random, dataInfo.file, offset);
539548
} else {
540-
InputStream stream = ClassicDecryptingPartInputStream.createFor(attachmentSecret, dataInfo.file);
549+
InputStream stream = ClassicDecryptingPartInputStream.createFor(attachmentSecret.get(), dataInfo.file);
541550
long skipped = stream.skip(offset);
542551

543552
if (skipped != offset) {
@@ -607,7 +616,7 @@ public void setTransferState(@NonNull AttachmentId attachmentId, int transferSta
607616
File dataFile = File.createTempFile("part", ".mms", partsDirectory);
608617

609618
Log.d("AttachmentDatabase", "Writing attachment data to: " + dataFile.getAbsolutePath());
610-
Pair<byte[], OutputStream> out = ModernEncryptingPartOutputStream.createFor(attachmentSecret, dataFile, false);
619+
Pair<byte[], OutputStream> out = ModernEncryptingPartOutputStream.createFor(attachmentSecret.get(), dataFile, false);
611620
long length = Util.copy(in, out.second);
612621

613622
return new DataInfo(dataFile, length, out.first);
@@ -894,7 +903,7 @@ private ThumbnailData generateVideoThumbnail(AttachmentId attachmentId) {
894903
return null;
895904
}
896905

897-
EncryptedMediaDataSource dataSource = new EncryptedMediaDataSource(attachmentSecret, dataInfo.file, dataInfo.random, dataInfo.length);
906+
EncryptedMediaDataSource dataSource = new EncryptedMediaDataSource(attachmentSecret.get(), dataInfo.file, dataInfo.random, dataInfo.length);
898907
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
899908
retriever.setDataSource(dataSource);
900909

app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseModule.kt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,6 @@ object DatabaseModule {
5454
return manager.openHelper
5555
}
5656

57-
@Provides
58-
@Singleton
59-
fun provideAttachmentDatabase(@ApplicationContext context: Context,
60-
openHelper: Provider<SQLCipherOpenHelper>,
61-
attachmentSecret: AttachmentSecret) = AttachmentDatabase(context, openHelper, attachmentSecret)
6257
@Provides
6358
@Singleton
6459
fun provideMediaDatbase(@ApplicationContext context: Context, openHelper: Provider<SQLCipherOpenHelper>) = MediaDatabase(context, openHelper)

app/src/main/java/org/thoughtcrime/securesms/glide/cache/EncryptedBitmapCacheDecoder.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,18 @@
22

33

44
import android.graphics.Bitmap;
5+
56
import androidx.annotation.NonNull;
67
import androidx.annotation.Nullable;
7-
import org.session.libsignal.utilities.Log;
88

99
import com.bumptech.glide.load.Options;
1010
import com.bumptech.glide.load.ResourceDecoder;
1111
import com.bumptech.glide.load.engine.Resource;
1212
import com.bumptech.glide.load.resource.bitmap.StreamBitmapDecoder;
1313

14+
import org.session.libsignal.utilities.Log;
15+
import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider;
16+
1417
import java.io.File;
1518
import java.io.IOException;
1619
import java.io.InputStream;
@@ -20,10 +23,10 @@ public class EncryptedBitmapCacheDecoder extends EncryptedCoder implements Resou
2023
private static final String TAG = EncryptedBitmapCacheDecoder.class.getSimpleName();
2124

2225
private final StreamBitmapDecoder streamBitmapDecoder;
23-
private final byte[] secret;
26+
private final AttachmentSecretProvider attachmentSecretProvider;
2427

25-
public EncryptedBitmapCacheDecoder(@NonNull byte[] secret, @NonNull StreamBitmapDecoder streamBitmapDecoder) {
26-
this.secret = secret;
28+
public EncryptedBitmapCacheDecoder(@NonNull AttachmentSecretProvider attachmentSecretProvider, @NonNull StreamBitmapDecoder streamBitmapDecoder) {
29+
this.attachmentSecretProvider = attachmentSecretProvider;
2730
this.streamBitmapDecoder = streamBitmapDecoder;
2831
}
2932

@@ -33,7 +36,7 @@ public boolean handles(@NonNull File source, @NonNull Options options)
3336
{
3437
Log.i(TAG, "Checking item for encrypted Bitmap cache decoder: " + source.toString());
3538

36-
try (InputStream inputStream = createEncryptedInputStream(secret, source)) {
39+
try (InputStream inputStream = createEncryptedInputStream(attachmentSecretProvider.getOrCreateAttachmentSecret().getModernKey(), source)) {
3740
return streamBitmapDecoder.handles(inputStream, options);
3841
} catch (IOException e) {
3942
Log.w(TAG, e);
@@ -47,7 +50,7 @@ public Resource<Bitmap> decode(@NonNull File source, int width, int height, @Non
4750
throws IOException
4851
{
4952
Log.i(TAG, "Encrypted Bitmap cache decoder running: " + source.toString());
50-
try (InputStream inputStream = createEncryptedInputStream(secret, source)) {
53+
try (InputStream inputStream = createEncryptedInputStream(attachmentSecretProvider.getOrCreateAttachmentSecret().getModernKey(), source)) {
5154
return streamBitmapDecoder.decode(inputStream, width, height, options);
5255
}
5356
}

app/src/main/java/org/thoughtcrime/securesms/glide/cache/EncryptedBitmapResourceEncoder.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import android.graphics.Bitmap;
55
import androidx.annotation.NonNull;
66
import org.session.libsignal.utilities.Log;
7+
import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider;
78

89
import com.bumptech.glide.load.EncodeStrategy;
910
import com.bumptech.glide.load.Options;
@@ -19,10 +20,10 @@ public class EncryptedBitmapResourceEncoder extends EncryptedCoder implements Re
1920

2021
private static final String TAG = EncryptedBitmapResourceEncoder.class.getSimpleName();
2122

22-
private final byte[] secret;
23+
private final AttachmentSecretProvider secretProvider;
2324

24-
public EncryptedBitmapResourceEncoder(@NonNull byte[] secret) {
25-
this.secret = secret;
25+
public EncryptedBitmapResourceEncoder(@NonNull AttachmentSecretProvider secretProvider) {
26+
this.secretProvider = secretProvider;
2627
}
2728

2829
@Override
@@ -39,7 +40,7 @@ public boolean encode(@NonNull Resource<Bitmap> data, @NonNull File file, @NonNu
3940
Bitmap.CompressFormat format = getFormat(bitmap, options);
4041
int quality = options.get(BitmapEncoder.COMPRESSION_QUALITY);
4142

42-
try (OutputStream os = createEncryptedOutputStream(secret, file)) {
43+
try (OutputStream os = createEncryptedOutputStream(secretProvider.getOrCreateAttachmentSecret().getModernKey(), file)) {
4344
bitmap.compress(format, quality, os);
4445
os.close();
4546
return true;

app/src/main/java/org/thoughtcrime/securesms/glide/cache/EncryptedCacheEncoder.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,31 @@
11
package org.thoughtcrime.securesms.glide.cache;
22

33

4-
import androidx.annotation.NonNull;
54

65
import com.bumptech.glide.load.Encoder;
76
import com.bumptech.glide.load.Options;
87
import com.bumptech.glide.load.engine.bitmap_recycle.ArrayPool;
98

9+
import org.jspecify.annotations.NonNull;
1010
import org.session.libsignal.utilities.Log;
11+
import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider;
1112

1213
import java.io.File;
1314
import java.io.IOException;
1415
import java.io.InputStream;
1516
import java.io.OutputStream;
1617

18+
import dagger.Lazy;
19+
1720
public class EncryptedCacheEncoder extends EncryptedCoder implements Encoder<InputStream> {
1821

1922
private static final String TAG = EncryptedCacheEncoder.class.getSimpleName();
2023

21-
private final byte[] secret;
24+
private final AttachmentSecretProvider attachmentSecretProvider;
2225
private final ArrayPool byteArrayPool;
2326

24-
public EncryptedCacheEncoder(@NonNull byte[] secret, @NonNull ArrayPool byteArrayPool) {
25-
this.secret = secret;
27+
public EncryptedCacheEncoder(AttachmentSecretProvider attachmentSecretProvider, @NonNull ArrayPool byteArrayPool) {
28+
this.attachmentSecretProvider = attachmentSecretProvider;
2629
this.byteArrayPool = byteArrayPool;
2730
}
2831

@@ -33,7 +36,7 @@ public boolean encode(@NonNull InputStream data, @NonNull File file, @NonNull Op
3336

3437
byte[] buffer = byteArrayPool.get(ArrayPool.STANDARD_BUFFER_SIZE_BYTES, byte[].class);
3538

36-
try (OutputStream outputStream = createEncryptedOutputStream(secret, file)) {
39+
try (OutputStream outputStream = createEncryptedOutputStream(attachmentSecretProvider.getOrCreateAttachmentSecret().getModernKey(), file)) {
3740
int read;
3841

3942
while ((read = data.read(buffer)) != -1) {

app/src/main/java/org/thoughtcrime/securesms/glide/cache/EncryptedGifCacheDecoder.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import androidx.annotation.NonNull;
55
import androidx.annotation.Nullable;
66
import org.session.libsignal.utilities.Log;
7+
import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider;
78

89
import com.bumptech.glide.load.Options;
910
import com.bumptech.glide.load.ResourceDecoder;
@@ -19,19 +20,19 @@ public class EncryptedGifCacheDecoder extends EncryptedCoder implements Resource
1920

2021
private static final String TAG = EncryptedGifCacheDecoder.class.getSimpleName();
2122

22-
private final byte[] secret;
23+
private final AttachmentSecretProvider attachmentSecretProvider;
2324
private final StreamGifDecoder gifDecoder;
2425

25-
public EncryptedGifCacheDecoder(@NonNull byte[] secret, @NonNull StreamGifDecoder gifDecoder) {
26-
this.secret = secret;
26+
public EncryptedGifCacheDecoder(@NonNull AttachmentSecretProvider attachmentSecretProvider, @NonNull StreamGifDecoder gifDecoder) {
27+
this.attachmentSecretProvider = attachmentSecretProvider;
2728
this.gifDecoder = gifDecoder;
2829
}
2930

3031
@Override
3132
public boolean handles(@NonNull File source, @NonNull Options options) {
3233
Log.i(TAG, "Checking item for encrypted GIF cache decoder: " + source.toString());
3334

34-
try (InputStream inputStream = createEncryptedInputStream(secret, source)) {
35+
try (InputStream inputStream = createEncryptedInputStream(attachmentSecretProvider.getOrCreateAttachmentSecret().getModernKey(), source)) {
3536
return gifDecoder.handles(inputStream, options);
3637
} catch (IOException e) {
3738
Log.w(TAG, e);
@@ -43,7 +44,7 @@ public boolean handles(@NonNull File source, @NonNull Options options) {
4344
@Override
4445
public Resource<GifDrawable> decode(@NonNull File source, int width, int height, @NonNull Options options) throws IOException {
4546
Log.i(TAG, "Encrypted GIF cache decoder running...");
46-
try (InputStream inputStream = createEncryptedInputStream(secret, source)) {
47+
try (InputStream inputStream = createEncryptedInputStream(attachmentSecretProvider.getOrCreateAttachmentSecret().getModernKey(), source)) {
4748
return gifDecoder.decode(inputStream, width, height, options);
4849
}
4950
}

app/src/main/java/org/thoughtcrime/securesms/glide/cache/EncryptedGifDrawableResourceEncoder.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import androidx.annotation.NonNull;
55
import org.session.libsignal.utilities.Log;
6+
import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider;
67

78
import com.bumptech.glide.load.EncodeStrategy;
89
import com.bumptech.glide.load.Options;
@@ -19,10 +20,10 @@ public class EncryptedGifDrawableResourceEncoder extends EncryptedCoder implemen
1920

2021
private static final String TAG = EncryptedGifDrawableResourceEncoder.class.getSimpleName();
2122

22-
private final byte[] secret;
23+
private final AttachmentSecretProvider secretProvider;
2324

24-
public EncryptedGifDrawableResourceEncoder(@NonNull byte[] secret) {
25-
this.secret = secret;
25+
public EncryptedGifDrawableResourceEncoder(@NonNull AttachmentSecretProvider secretProvider) {
26+
this.secretProvider = secretProvider;
2627
}
2728

2829
@Override
@@ -34,7 +35,7 @@ public EncodeStrategy getEncodeStrategy(@NonNull Options options) {
3435
public boolean encode(@NonNull Resource<GifDrawable> data, @NonNull File file, @NonNull Options options) {
3536
GifDrawable drawable = data.get();
3637

37-
try (OutputStream outputStream = createEncryptedOutputStream(secret, file)) {
38+
try (OutputStream outputStream = createEncryptedOutputStream(secretProvider.getOrCreateAttachmentSecret().getModernKey(), file)) {
3839
ByteBufferUtil.toStream(drawable.getBuffer(), outputStream);
3940
return true;
4041
} catch (IOException e) {

app/src/main/java/org/thoughtcrime/securesms/logging/PersistentLogger.kt

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ class PersistentLogger @Inject constructor(
5858
var logWriter: LogFile.Writer? = null
5959
val entryBuilder = StringBuilder()
6060

61-
try {
62-
while (true) {
61+
while (true) {
62+
try {
6363
channel.receiveBulkLogs(bulk)
6464

6565
if (bulk.isNotEmpty()) {
@@ -92,18 +92,18 @@ class PersistentLogger @Inject constructor(
9292
logWriter = null
9393
}
9494
}
95-
96-
// Notify that the log channel is idle
97-
logChannelIdleSignal.tryEmit(Unit)
95+
} catch (e: Throwable) {
96+
logWriter?.close()
97+
98+
android.util.Log.e(
99+
TAG,
100+
"Error while processing log entries: ${e.message}",
101+
e
102+
)
98103
}
99-
} catch (e: Exception) {
100-
logWriter?.close()
101-
102-
android.util.Log.e(
103-
TAG,
104-
"Error while processing log entries: ${e.message}",
105-
e
106-
)
104+
105+
// Notify that the log channel is idle
106+
logChannelIdleSignal.tryEmit(Unit)
107107
}
108108
}
109109
}

app/src/main/java/org/thoughtcrime/securesms/mms/SignalGlideModule.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,15 @@ public void applyOptions(Context context, GlideBuilder builder) {
5757

5858
@Override
5959
public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
60-
AttachmentSecret attachmentSecret = AttachmentSecretProvider.getInstance(context).getOrCreateAttachmentSecret();
61-
byte[] secret = attachmentSecret.getModernKey();
60+
AttachmentSecretProvider secretProvider = AttachmentSecretProvider.getInstance(context);
6261

6362
registry.prepend(File.class, File.class, UnitModelLoader.Factory.getInstance());
64-
registry.prepend(InputStream.class, new EncryptedCacheEncoder(secret, glide.getArrayPool()));
65-
registry.prepend(File.class, Bitmap.class, new EncryptedBitmapCacheDecoder(secret, new StreamBitmapDecoder(new Downsampler(registry.getImageHeaderParsers(), context.getResources().getDisplayMetrics(), glide.getBitmapPool(), glide.getArrayPool()), glide.getArrayPool())));
66-
registry.prepend(File.class, GifDrawable.class, new EncryptedGifCacheDecoder(secret, new StreamGifDecoder(registry.getImageHeaderParsers(), new ByteBufferGifDecoder(context, registry.getImageHeaderParsers(), glide.getBitmapPool(), glide.getArrayPool()), glide.getArrayPool())));
63+
registry.prepend(InputStream.class, new EncryptedCacheEncoder(secretProvider, glide.getArrayPool()));
64+
registry.prepend(File.class, Bitmap.class, new EncryptedBitmapCacheDecoder(secretProvider, new StreamBitmapDecoder(new Downsampler(registry.getImageHeaderParsers(), context.getResources().getDisplayMetrics(), glide.getBitmapPool(), glide.getArrayPool()), glide.getArrayPool())));
65+
registry.prepend(File.class, GifDrawable.class, new EncryptedGifCacheDecoder(secretProvider, new StreamGifDecoder(registry.getImageHeaderParsers(), new ByteBufferGifDecoder(context, registry.getImageHeaderParsers(), glide.getBitmapPool(), glide.getArrayPool()), glide.getArrayPool())));
6766

68-
registry.prepend(Bitmap.class, new EncryptedBitmapResourceEncoder(secret));
69-
registry.prepend(GifDrawable.class, new EncryptedGifDrawableResourceEncoder(secret));
67+
registry.prepend(Bitmap.class, new EncryptedBitmapResourceEncoder(secretProvider));
68+
registry.prepend(GifDrawable.class, new EncryptedGifDrawableResourceEncoder(secretProvider));
7069

7170
registry.append(RemoteFile.class, InputStream.class, new RemoteFileLoader.Factory(
7271
((ApplicationContext) (context.getApplicationContext())).getRemoteFileLoader()

0 commit comments

Comments
 (0)