kopia lustrzana https://github.com/ryukoposting/Signal-Android
Simple encrypted glide disk cache
rodzic
7e1e666172
commit
95d76638dc
|
@ -142,7 +142,7 @@ public class ThumbnailView extends FrameLayout {
|
|||
if (transferControls.isPresent()) getTransferControls().setVisibility(View.GONE);
|
||||
|
||||
glideRequests.load(new DecryptableUri(uri))
|
||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
||||
.transform(new RoundedCorners(radius))
|
||||
.transition(withCrossFade())
|
||||
.centerCrop()
|
||||
|
@ -173,7 +173,7 @@ public class ThumbnailView extends FrameLayout {
|
|||
|
||||
private RequestBuilder buildThumbnailGlideRequest(@NonNull GlideRequests glideRequests, @NonNull Slide slide) {
|
||||
RequestBuilder builder = glideRequests.load(new DecryptableUri(slide.getThumbnailUri()))
|
||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
||||
.transform(new RoundedCorners(radius))
|
||||
.centerCrop()
|
||||
.transition(withCrossFade());
|
||||
|
|
|
@ -65,7 +65,7 @@ public class AttachmentSecret {
|
|||
}
|
||||
|
||||
@JsonIgnore
|
||||
byte[] getModernKey() {
|
||||
public byte[] getModernKey() {
|
||||
return modernKey;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.thoughtcrime.securesms.giph.ui;
|
||||
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
|
@ -19,6 +20,7 @@ import android.widget.Toast;
|
|||
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.providers.PersistentBlobProvider;
|
||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
|
@ -98,6 +100,7 @@ public class GiphyActivity extends PassphraseRequiredActionBarActivity
|
|||
this.stickerFragment.setLayoutManager(type);
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
@Override
|
||||
public void onClick(final GiphyAdapter.GiphyViewHolder viewHolder) {
|
||||
if (finishingImage != null) finishingImage.gifProgress.setVisibility(View.GONE);
|
||||
|
@ -108,7 +111,9 @@ public class GiphyActivity extends PassphraseRequiredActionBarActivity
|
|||
@Override
|
||||
protected Uri doInBackground(Void... params) {
|
||||
try {
|
||||
return Uri.fromFile(viewHolder.getFile(forMms));
|
||||
byte[] data = viewHolder.getData(forMms);
|
||||
|
||||
return PersistentBlobProvider.getInstance(GiphyActivity.this).create(GiphyActivity.this, data, "image/gif", null);
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
Log.w(TAG, e);
|
||||
return null;
|
||||
|
|
|
@ -13,13 +13,16 @@ import android.view.View;
|
|||
import android.view.ViewGroup;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.RequestBuilder;
|
||||
import com.bumptech.glide.load.DataSource;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
import com.bumptech.glide.load.engine.GlideException;
|
||||
import com.bumptech.glide.load.resource.gif.GifDrawable;
|
||||
import com.bumptech.glide.load.resource.gif.GifDrawableEncoder;
|
||||
import com.bumptech.glide.load.resource.gif.GifDrawableResource;
|
||||
import com.bumptech.glide.request.RequestListener;
|
||||
import com.bumptech.glide.request.target.Target;
|
||||
import com.bumptech.glide.util.ByteBufferUtil;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.color.MaterialColor;
|
||||
|
@ -32,7 +35,10 @@ import org.thoughtcrime.securesms.util.ViewUtil;
|
|||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
|
@ -94,17 +100,20 @@ class GiphyAdapter extends RecyclerView.Adapter<GiphyAdapter.GiphyViewHolder> {
|
|||
}
|
||||
|
||||
|
||||
public File getFile(boolean forMms) throws ExecutionException, InterruptedException {
|
||||
public byte[] getData(boolean forMms) throws ExecutionException, InterruptedException {
|
||||
synchronized (this) {
|
||||
while (!modelReady) {
|
||||
Util.wait(this, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return glideRequests.load(forMms ? new GiphyPaddedUrl(image.getGifMmsUrl(), image.getMmsGifSize()) :
|
||||
new GiphyPaddedUrl(image.getGifUrl(), image.getGifSize()))
|
||||
.downloadOnly(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
|
||||
.get();
|
||||
GifDrawable drawable = glideRequests.asGif()
|
||||
.load(forMms ? new GiphyPaddedUrl(image.getGifMmsUrl(), image.getMmsGifSize()) :
|
||||
new GiphyPaddedUrl(image.getGifUrl(), image.getGifSize()))
|
||||
.submit(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
|
||||
.get();
|
||||
|
||||
return ByteBufferUtil.toBytes(drawable.getBuffer());
|
||||
}
|
||||
|
||||
public synchronized void setModelReady() {
|
||||
|
|
|
@ -45,7 +45,7 @@ class GiphyPaddedUrlFetcher implements DataFetcher<InputStream> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void loadData(Priority priority, DataCallback<? super InputStream> callback) {
|
||||
public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
|
||||
bodies = new LinkedList<>();
|
||||
rangeStreams = new LinkedList<>();
|
||||
stream = null;
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
package org.thoughtcrime.securesms.glide.cache;
|
||||
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import com.bumptech.glide.load.Options;
|
||||
import com.bumptech.glide.load.ResourceDecoder;
|
||||
import com.bumptech.glide.load.engine.Resource;
|
||||
import com.bumptech.glide.load.resource.bitmap.StreamBitmapDecoder;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class EncryptedBitmapCacheDecoder extends EncryptedCoder implements ResourceDecoder<File, Bitmap> {
|
||||
|
||||
private static final String TAG = EncryptedBitmapCacheDecoder.class.getSimpleName();
|
||||
|
||||
private final StreamBitmapDecoder streamBitmapDecoder;
|
||||
private final byte[] secret;
|
||||
|
||||
public EncryptedBitmapCacheDecoder(@NonNull byte[] secret, @NonNull StreamBitmapDecoder streamBitmapDecoder) {
|
||||
this.secret = secret;
|
||||
this.streamBitmapDecoder = streamBitmapDecoder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handles(@NonNull File source, @NonNull Options options)
|
||||
throws IOException
|
||||
{
|
||||
Log.w(TAG, "Checking item for encrypted Bitmap cache decoder: " + source.toString());
|
||||
|
||||
try (InputStream inputStream = createEncryptedInputStream(secret, source)) {
|
||||
return streamBitmapDecoder.handles(inputStream, options);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Resource<Bitmap> decode(@NonNull File source, int width, int height, @NonNull Options options)
|
||||
throws IOException
|
||||
{
|
||||
Log.w(TAG, "Encrypted Bitmap cache decoder running: " + source.toString());
|
||||
try (InputStream inputStream = createEncryptedInputStream(secret, source)) {
|
||||
return streamBitmapDecoder.decode(inputStream, width, height, options);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package org.thoughtcrime.securesms.glide.cache;
|
||||
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import com.bumptech.glide.load.EncodeStrategy;
|
||||
import com.bumptech.glide.load.Options;
|
||||
import com.bumptech.glide.load.ResourceEncoder;
|
||||
import com.bumptech.glide.load.engine.Resource;
|
||||
import com.bumptech.glide.load.resource.bitmap.BitmapEncoder;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class EncryptedBitmapResourceEncoder extends EncryptedCoder implements ResourceEncoder<Bitmap> {
|
||||
|
||||
private static final String TAG = EncryptedBitmapResourceEncoder.class.getSimpleName();
|
||||
|
||||
private final byte[] secret;
|
||||
|
||||
public EncryptedBitmapResourceEncoder(@NonNull byte[] secret) {
|
||||
this.secret = secret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EncodeStrategy getEncodeStrategy(@NonNull Options options) {
|
||||
return EncodeStrategy.TRANSFORMED;
|
||||
}
|
||||
|
||||
@SuppressWarnings("EmptyCatchBlock")
|
||||
@Override
|
||||
public boolean encode(@NonNull Resource<Bitmap> data, @NonNull File file, @NonNull Options options) {
|
||||
Log.w(TAG, "Encrypted resource encoder running: " + file.toString());
|
||||
|
||||
Bitmap bitmap = data.get();
|
||||
Bitmap.CompressFormat format = getFormat(bitmap, options);
|
||||
int quality = options.get(BitmapEncoder.COMPRESSION_QUALITY);
|
||||
|
||||
try (OutputStream os = createEncryptedOutputStream(secret, file)) {
|
||||
bitmap.compress(format, quality, os);
|
||||
os.close();
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private Bitmap.CompressFormat getFormat(Bitmap bitmap, Options options) {
|
||||
Bitmap.CompressFormat format = options.get(BitmapEncoder.COMPRESSION_FORMAT);
|
||||
|
||||
if (format != null) {
|
||||
return format;
|
||||
} else if (bitmap.hasAlpha()) {
|
||||
return Bitmap.CompressFormat.PNG;
|
||||
} else {
|
||||
return Bitmap.CompressFormat.JPEG;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package org.thoughtcrime.securesms.glide.cache;
|
||||
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import com.bumptech.glide.load.Encoder;
|
||||
import com.bumptech.glide.load.Options;
|
||||
import com.bumptech.glide.load.engine.bitmap_recycle.ArrayPool;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class EncryptedCacheEncoder extends EncryptedCoder implements Encoder<InputStream> {
|
||||
|
||||
private static final String TAG = EncryptedCacheEncoder.class.getSimpleName();
|
||||
|
||||
private final byte[] secret;
|
||||
private final ArrayPool byteArrayPool;
|
||||
|
||||
public EncryptedCacheEncoder(@NonNull byte[] secret, @NonNull ArrayPool byteArrayPool) {
|
||||
this.secret = secret;
|
||||
this.byteArrayPool = byteArrayPool;
|
||||
}
|
||||
|
||||
@SuppressWarnings("EmptyCatchBlock")
|
||||
@Override
|
||||
public boolean encode(@NonNull InputStream data, @NonNull File file, @NonNull Options options) {
|
||||
Log.w(TAG, "Encrypted cache encoder running: " + file.toString());
|
||||
|
||||
byte[] buffer = byteArrayPool.get(ArrayPool.STANDARD_BUFFER_SIZE_BYTES, byte[].class);
|
||||
|
||||
try (OutputStream outputStream = createEncryptedOutputStream(secret, file)) {
|
||||
int read;
|
||||
|
||||
while ((read = data.read(buffer)) != -1) {
|
||||
outputStream.write(buffer, 0, read);
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
return false;
|
||||
} finally {
|
||||
byteArrayPool.put(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
package org.thoughtcrime.securesms.glide.cache;
|
||||
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.CipherInputStream;
|
||||
import javax.crypto.CipherOutputStream;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
class EncryptedCoder {
|
||||
|
||||
private static byte[] MAGIC_BYTES = {(byte)0x91, (byte)0x5e, (byte)0x6d, (byte)0xb4,
|
||||
(byte)0x09, (byte)0xa6, (byte)0x68, (byte)0xbe,
|
||||
(byte)0xe5, (byte)0xb1, (byte)0x1b, (byte)0xd7,
|
||||
(byte)0x29, (byte)0xe5, (byte)0x04, (byte)0xcc};
|
||||
|
||||
OutputStream createEncryptedOutputStream(@NonNull byte[] masterKey, @NonNull File file)
|
||||
throws IOException
|
||||
{
|
||||
try {
|
||||
byte[] random = Util.getSecretBytes(32);
|
||||
Mac mac = Mac.getInstance("HmacSHA256");
|
||||
mac.init(new SecretKeySpec(masterKey, "HmacSHA256"));
|
||||
|
||||
FileOutputStream fileOutputStream = new FileOutputStream(file);
|
||||
byte[] iv = new byte[16];
|
||||
byte[] key = mac.doFinal(random);
|
||||
|
||||
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));
|
||||
|
||||
fileOutputStream.write(MAGIC_BYTES);
|
||||
fileOutputStream.write(random);
|
||||
|
||||
CipherOutputStream outputStream = new CipherOutputStream(fileOutputStream, cipher);
|
||||
outputStream.write(MAGIC_BYTES);
|
||||
|
||||
return outputStream;
|
||||
} catch (NoSuchAlgorithmException | InvalidKeyException | NoSuchPaddingException | InvalidAlgorithmParameterException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
InputStream createEncryptedInputStream(@NonNull byte[] masterKey, @NonNull File file) throws IOException {
|
||||
try {
|
||||
Mac mac = Mac.getInstance("HmacSHA256");
|
||||
mac.init(new SecretKeySpec(masterKey, "HmacSHA256"));
|
||||
|
||||
FileInputStream fileInputStream = new FileInputStream(file);
|
||||
byte[] theirMagic = new byte[MAGIC_BYTES.length];
|
||||
byte[] theirRandom = new byte[32];
|
||||
byte[] theirEncryptedMagic = new byte[MAGIC_BYTES.length];
|
||||
|
||||
Util.readFully(fileInputStream, theirMagic);
|
||||
Util.readFully(fileInputStream, theirRandom);
|
||||
|
||||
if (!MessageDigest.isEqual(theirMagic, MAGIC_BYTES)) {
|
||||
throw new IOException("Not an encrypted cache file!");
|
||||
}
|
||||
|
||||
byte[] iv = new byte[16];
|
||||
byte[] key = mac.doFinal(theirRandom);
|
||||
|
||||
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
|
||||
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));
|
||||
|
||||
CipherInputStream inputStream = new CipherInputStream(fileInputStream, cipher);
|
||||
Util.readFully(inputStream, theirEncryptedMagic);
|
||||
|
||||
if (!MessageDigest.isEqual(theirEncryptedMagic, MAGIC_BYTES)) {
|
||||
throw new IOException("Key change on encrypted cache file!");
|
||||
}
|
||||
|
||||
return inputStream;
|
||||
} catch (NoSuchAlgorithmException | InvalidKeyException | NoSuchPaddingException | InvalidAlgorithmParameterException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package org.thoughtcrime.securesms.glide.cache;
|
||||
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import com.bumptech.glide.load.Options;
|
||||
import com.bumptech.glide.load.ResourceDecoder;
|
||||
import com.bumptech.glide.load.engine.Resource;
|
||||
import com.bumptech.glide.load.resource.gif.GifDrawable;
|
||||
import com.bumptech.glide.load.resource.gif.StreamGifDecoder;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class EncryptedGifCacheDecoder extends EncryptedCoder implements ResourceDecoder<File, GifDrawable> {
|
||||
|
||||
private static final String TAG = EncryptedGifCacheDecoder.class.getSimpleName();
|
||||
|
||||
private final byte[] secret;
|
||||
private final StreamGifDecoder gifDecoder;
|
||||
|
||||
public EncryptedGifCacheDecoder(@NonNull byte[] secret, @NonNull StreamGifDecoder gifDecoder) {
|
||||
this.secret = secret;
|
||||
this.gifDecoder = gifDecoder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handles(@NonNull File source, @NonNull Options options) {
|
||||
Log.w(TAG, "Checking item for encrypted GIF cache decoder: " + source.toString());
|
||||
|
||||
try (InputStream inputStream = createEncryptedInputStream(secret, source)) {
|
||||
return gifDecoder.handles(inputStream, options);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Resource<GifDrawable> decode(@NonNull File source, int width, int height, @NonNull Options options) throws IOException {
|
||||
Log.w(TAG, "Encrypted GIF cache decoder running...");
|
||||
try (InputStream inputStream = createEncryptedInputStream(secret, source)) {
|
||||
return gifDecoder.decode(inputStream, width, height, options);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package org.thoughtcrime.securesms.glide.cache;
|
||||
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import com.bumptech.glide.load.EncodeStrategy;
|
||||
import com.bumptech.glide.load.Options;
|
||||
import com.bumptech.glide.load.ResourceEncoder;
|
||||
import com.bumptech.glide.load.engine.Resource;
|
||||
import com.bumptech.glide.load.resource.gif.GifDrawable;
|
||||
import com.bumptech.glide.util.ByteBufferUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class EncryptedGifDrawableResourceEncoder extends EncryptedCoder implements ResourceEncoder<GifDrawable> {
|
||||
|
||||
private static final String TAG = EncryptedGifDrawableResourceEncoder.class.getSimpleName();
|
||||
|
||||
private final byte[] secret;
|
||||
|
||||
public EncryptedGifDrawableResourceEncoder(@NonNull byte[] secret) {
|
||||
this.secret = secret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EncodeStrategy getEncodeStrategy(@NonNull Options options) {
|
||||
return EncodeStrategy.TRANSFORMED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean encode(@NonNull Resource<GifDrawable> data, @NonNull File file, @NonNull Options options) {
|
||||
GifDrawable drawable = data.get();
|
||||
|
||||
try (OutputStream outputStream = createEncryptedOutputStream(secret, file)) {
|
||||
ByteBufferUtil.toStream(drawable.getBuffer(), outputStream);
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -208,7 +208,7 @@ public class AttachmentManager {
|
|||
{
|
||||
inflateStub();
|
||||
|
||||
new AsyncTask<Void, Void, Slide>() {
|
||||
new AsyncTask<Void, Void, Slide>() {
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
thumbnail.clear(glideRequests);
|
||||
|
|
|
@ -47,10 +47,7 @@ public class ImageSlide extends Slide {
|
|||
|
||||
@Override
|
||||
public @Nullable Uri getThumbnailUri() {
|
||||
Uri thumbnailUri = super.getThumbnailUri();
|
||||
|
||||
if (thumbnailUri == null) return getUri();
|
||||
else return thumbnailUri;
|
||||
return getUri();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package org.thoughtcrime.securesms.mms;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
|
@ -10,16 +12,29 @@ import com.bumptech.glide.annotation.GlideModule;
|
|||
import com.bumptech.glide.load.engine.cache.DiskCache;
|
||||
import com.bumptech.glide.load.engine.cache.DiskCacheAdapter;
|
||||
import com.bumptech.glide.load.model.GlideUrl;
|
||||
import com.bumptech.glide.load.resource.bitmap.Downsampler;
|
||||
import com.bumptech.glide.load.resource.bitmap.StreamBitmapDecoder;
|
||||
import com.bumptech.glide.load.resource.gif.ByteBufferGifDecoder;
|
||||
import com.bumptech.glide.load.resource.gif.GifDrawable;
|
||||
import com.bumptech.glide.load.resource.gif.StreamGifDecoder;
|
||||
import com.bumptech.glide.module.AppGlideModule;
|
||||
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
|
||||
import org.thoughtcrime.securesms.crypto.AttachmentSecret;
|
||||
import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider;
|
||||
import org.thoughtcrime.securesms.giph.model.GiphyPaddedUrl;
|
||||
import org.thoughtcrime.securesms.glide.ContactPhotoLoader;
|
||||
import org.thoughtcrime.securesms.glide.cache.EncryptedBitmapCacheDecoder;
|
||||
import org.thoughtcrime.securesms.glide.cache.EncryptedCacheEncoder;
|
||||
import org.thoughtcrime.securesms.glide.cache.EncryptedGifCacheDecoder;
|
||||
import org.thoughtcrime.securesms.glide.cache.EncryptedBitmapResourceEncoder;
|
||||
import org.thoughtcrime.securesms.glide.cache.EncryptedGifDrawableResourceEncoder;
|
||||
import org.thoughtcrime.securesms.glide.GiphyPaddedUrlLoader;
|
||||
import org.thoughtcrime.securesms.glide.OkHttpUrlLoader;
|
||||
import org.thoughtcrime.securesms.mms.AttachmentStreamUriLoader.AttachmentModel;
|
||||
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
|
||||
@GlideModule
|
||||
|
@ -37,7 +52,17 @@ public class SignalGlideModule extends AppGlideModule {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void registerComponents(Context context, Glide glide, Registry registry) {
|
||||
public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
|
||||
AttachmentSecret attachmentSecret = AttachmentSecretProvider.getInstance(context).getOrCreateAttachmentSecret();
|
||||
byte[] secret = attachmentSecret.getModernKey();
|
||||
|
||||
registry.prepend(InputStream.class, new EncryptedCacheEncoder(secret, glide.getArrayPool()));
|
||||
registry.prepend(File.class, Bitmap.class, new EncryptedBitmapCacheDecoder(secret, new StreamBitmapDecoder(new Downsampler(registry.getImageHeaderParsers(), context.getResources().getDisplayMetrics(), glide.getBitmapPool(), glide.getArrayPool()), glide.getArrayPool())));
|
||||
registry.prepend(File.class, GifDrawable.class, new EncryptedGifCacheDecoder(secret, new StreamGifDecoder(registry.getImageHeaderParsers(), new ByteBufferGifDecoder(context, registry.getImageHeaderParsers(), glide.getBitmapPool(), glide.getArrayPool()), glide.getArrayPool())));
|
||||
|
||||
registry.prepend(Bitmap.class, new EncryptedBitmapResourceEncoder(secret));
|
||||
registry.prepend(GifDrawable.class, new EncryptedGifDrawableResourceEncoder(secret));
|
||||
|
||||
registry.append(ContactPhoto.class, InputStream.class, new ContactPhotoLoader.Factory(context));
|
||||
registry.append(DecryptableUri.class, InputStream.class, new DecryptableStreamUriLoader.Factory(context));
|
||||
registry.append(AttachmentModel.class, InputStream.class, new AttachmentStreamUriLoader.Factory());
|
||||
|
|
|
@ -14,6 +14,7 @@ import java.util.Map;
|
|||
|
||||
public class SingleUseBlobProvider {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = SingleUseBlobProvider.class.getSimpleName();
|
||||
|
||||
public static final String AUTHORITY = "org.thoughtcrime.securesms";
|
||||
|
|
Ładowanie…
Reference in New Issue