Support for attachment digests

// FREEBIE
This commit is contained in:
Moxie Marlinspike 2017-02-26 10:06:27 -08:00
parent a37d2f568c
commit 79e925051a
15 changed files with 89 additions and 33 deletions

View File

@ -57,7 +57,7 @@ dependencies {
compile 'org.whispersystems:jobmanager:1.0.2'
compile 'org.whispersystems:libpastelog:1.0.7'
compile 'org.whispersystems:signal-service-android:2.5.1'
compile 'org.whispersystems:signal-service-android:2.5.2'
compile 'org.whispersystems:webrtc-android:M57'
compile "me.leolin:ShortcutBadger:1.10-WS1"
@ -127,7 +127,7 @@ dependencyVerification {
'com.google.android.gms:play-services-places:abf3a4a3b146ec7e6e753be62775e512868cf37d6f88ffe2d81167b33b57132b',
'org.whispersystems:jobmanager:506f679fc2fcf7bb6d10f00f41d6f6ea0abf75c70dc95b913398661ad538a181',
'org.whispersystems:libpastelog:bb331d9a98240fc139101128ba836c1edec3c40e000597cdbb29ebf4cbf34d88',
'org.whispersystems:signal-service-android:b0329b155cc9ad5e7fc08e4660538df1827c6d9485b05cab41946f36ad7ee0ab',
'org.whispersystems:signal-service-android:030294f4f1517f032892f8100e649ac2ee6db39cf5cfaf42b00cc22ccd66b14b',
'org.whispersystems:webrtc-android:acf78f6148c2e946b846cc5395887079ba37ddb892bf0d993fed18f1b9f521f8',
'me.leolin:ShortcutBadger:e8e39df8a59d8211a30f40b1eeab21b3fa57b3f3e0f03abb995f82d66588778c',
'se.emilsjolander:stickylistheaders:a08ca948aa6b220f09d82f16bbbac395f6b78897e9eeac6a9f0b0ba755928eeb',
@ -162,22 +162,22 @@ dependencyVerification {
'com.google.android.gms:play-services-base:0ca636a8fc9a5af45e607cdcd61783bf5d561cbbb0f862021ce69606eee5ad49',
'com.google.android.gms:play-services-basement:95dd882c5ffba15b9a99de3fefb05d3a01946623af67454ca00055d222f85a8d',
'com.google.android.gms:play-services-iid:54e919f9957b8b7820da7ee9b83471d00d0cac1cf08ddea8b5b41aea80bb1a70',
'org.whispersystems:signal-service-java:e0b9c41fcf614d58a71afcbb290d1864275b65364ca8fafeb5fbcbdc2d59a57a',
'org.whispersystems:signal-protocol-android:1b4b9d557c8eaf861797ff683990d482d4aa8e9f23d9b17ff0cc67a02f38cb19',
'org.whispersystems:signal-service-java:49664fb9aedb6c39b303d20d167fa61bc25dc8d8bb148713ac29783383da1e90',
'com.nineoldandroids:library:68025a14e3e7673d6ad2f95e4b46d78d7d068343aa99256b686fe59de1b3163a',
'javax.inject:javax.inject:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'com.madgag.spongycastle:core:8d6240b974b0aca4d3da9c7dd44d42339d8a374358aca5fc98e50a995764511f',
'com.google.android.gms:play-services-tasks:69ec265168e601d0203d04cd42e34bb019b2f029aa1e16fabd38a5153eea2086',
'org.whispersystems:curve25519-android:bf6c34223d45d2f2813a8efcab9923caf99115115c760c9acea680bcb42d23c0',
'org.whispersystems:signal-protocol-java:a835cd0609cf116a74651bd0aa748db9392bba48c2d2af787757b8a1b50d131c',
'com.google.protobuf:protobuf-java:e0c1c64575c005601725e7c6a02cebf9e1285e888f756b2a1d73ffa8d725cc74',
'com.googlecode.libphonenumber:libphonenumber:141ebcafba7070a13d879c44e7648ddbe10beab665cb64d7b0c1bea93afb8dc2',
'com.fasterxml.jackson.core:jackson-databind:835097bcdd11f5bc8a08378c70d4c8054dfa4b911691cc2752063c75534d198d',
'com.squareup.okhttp3:okhttp:a992938d7203ca557cd7a116f002e8c427ec9cdae7ea852441abb8aec891f948',
'org.whispersystems:curve25519-android:bf6c34223d45d2f2813a8efcab9923caf99115115c760c9acea680bcb42d23c0',
'org.whispersystems:signal-protocol-java:a835cd0609cf116a74651bd0aa748db9392bba48c2d2af787757b8a1b50d131c',
'org.whispersystems:curve25519-java:00f1d4919f759055f41f7853a3d475dc7c8decf0dbf045ae93414f8f23b066cc',
'com.fasterxml.jackson.core:jackson-annotations:0ca408c24202a7626ec8b861e99d85eca5e38b73311dd6dd12e3e9deecc3fe94',
'com.fasterxml.jackson.core:jackson-core:cbf4604784b4de226262845447a1ad3bb38a6728cebe86562e2c5afada8be2c0',
'com.squareup.okio:okio:8c5436cadfab36bbd97db5f5c43b7bfdb5bf2f5f894ec8709b1929f14bdd010c',
'org.whispersystems:curve25519-java:00f1d4919f759055f41f7853a3d475dc7c8decf0dbf045ae93414f8f23b066cc',
'com.android.support:support-media-compat:8d6a1a5ba3d9eb1a25cb8f21bb312ac6280202e3d2900cb0b447d065d0d8a125',
'com.android.support:support-core-utils:a7649e18c04143dde40c218c5ce9a030e7ae674089cd7b18c6cf8ed2a22cf01a',
'com.android.support:support-fragment:1294500b357f52cf3779e2521c79f54ae7844f3b9a5f6727495dbbda7f231377',

View File

@ -22,8 +22,12 @@ public abstract class Attachment {
@Nullable
private final String relay;
@Nullable
private final byte[] digest;
public Attachment(@NonNull String contentType, int transferState, long size,
@Nullable String location, @Nullable String key, @Nullable String relay)
@Nullable String location, @Nullable String key, @Nullable String relay,
@Nullable byte[] digest)
{
this.contentType = contentType;
this.transferState = transferState;
@ -31,6 +35,7 @@ public abstract class Attachment {
this.location = location;
this.key = key;
this.relay = relay;
this.digest = digest;
}
@Nullable
@ -71,4 +76,9 @@ public abstract class Attachment {
public String getRelay() {
return relay;
}
@Nullable
public byte[] getDigest() {
return digest;
}
}

View File

@ -15,9 +15,9 @@ public class DatabaseAttachment extends Attachment {
public DatabaseAttachment(AttachmentId attachmentId, long mmsId,
boolean hasData, boolean hasThumbnail,
String contentType, int transferProgress, long size,
String location, String key, String relay)
String location, String key, String relay, byte[] digest)
{
super(contentType, transferProgress, size, location, key, relay);
super(contentType, transferProgress, size, location, key, relay, digest);
this.attachmentId = attachmentId;
this.hasData = hasData;
this.hasThumbnail = hasThumbnail;

View File

@ -10,7 +10,7 @@ import org.thoughtcrime.securesms.database.MmsDatabase;
public class MmsNotificationAttachment extends Attachment {
public MmsNotificationAttachment(int status, long size) {
super("application/mms", getTransferStateFromStatus(status), size, null, null, null);
super("application/mms", getTransferStateFromStatus(status), size, null, null, null, null);
}
@Nullable

View File

@ -16,9 +16,10 @@ import java.util.List;
public class PointerAttachment extends Attachment {
public PointerAttachment(@NonNull String contentType, int transferState, long size,
@NonNull String location, @NonNull String key, @NonNull String relay)
@NonNull String location, @NonNull String key, @NonNull String relay,
@Nullable byte[] digest)
{
super(contentType, transferState, size, location, key, relay);
super(contentType, transferState, size, location, key, relay, digest);
}
@Nullable
@ -45,7 +46,8 @@ public class PointerAttachment extends Attachment {
AttachmentDatabase.TRANSFER_PROGRESS_AUTO_PENDING,
pointer.asPointer().getSize().or(0),
String.valueOf(pointer.asPointer().getId()),
encryptedKey, pointer.asPointer().getRelay().orNull()));
encryptedKey, pointer.asPointer().getRelay().orNull(),
pointer.asPointer().getDigest().orNull()));
}
}
}

View File

@ -16,7 +16,7 @@ public class UriAttachment extends Attachment {
public UriAttachment(@NonNull Uri dataUri, @Nullable Uri thumbnailUri,
@NonNull String contentType, int transferState, long size)
{
super(contentType, transferState, size, null, null, null);
super(contentType, transferState, size, null, null, null, null);
this.dataUri = dataUri;
this.thumbnailUri = thumbnailUri;
}

View File

@ -79,6 +79,7 @@ public class AttachmentDatabase extends Database {
static final String THUMBNAIL = "thumbnail";
static final String THUMBNAIL_ASPECT_RATIO = "aspect_ratio";
static final String UNIQUE_ID = "unique_id";
static final String DIGEST = "digest";
public static final int TRANSFER_PROGRESS_DONE = 0;
public static final int TRANSFER_PROGRESS_STARTED = 1;
@ -91,7 +92,7 @@ public class AttachmentDatabase extends Database {
MMS_ID, CONTENT_TYPE, NAME, CONTENT_DISPOSITION,
CONTENT_LOCATION, DATA, THUMBNAIL, TRANSFER_STATE,
SIZE, THUMBNAIL, THUMBNAIL_ASPECT_RATIO,
UNIQUE_ID};
UNIQUE_ID, DIGEST};
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ROW_ID + " INTEGER PRIMARY KEY, " +
MMS_ID + " INTEGER, " + "seq" + " INTEGER DEFAULT 0, " +
@ -100,7 +101,8 @@ public class AttachmentDatabase extends Database {
CONTENT_LOCATION + " TEXT, " + "ctt_s" + " INTEGER, " +
"ctt_t" + " TEXT, " + "encrypted" + " INTEGER, " +
TRANSFER_STATE + " INTEGER, "+ DATA + " TEXT, " + SIZE + " INTEGER, " +
THUMBNAIL + " TEXT, " + THUMBNAIL_ASPECT_RATIO + " REAL, " + UNIQUE_ID + " INTEGER NOT NULL);";
THUMBNAIL + " TEXT, " + THUMBNAIL_ASPECT_RATIO + " REAL, " + UNIQUE_ID + " INTEGER NOT NULL, " +
DIGEST + " BLOB);";
public static final String[] CREATE_INDEXS = {
"CREATE INDEX IF NOT EXISTS part_mms_id_index ON " + TABLE_NAME + " (" + MMS_ID + ");",
@ -266,6 +268,7 @@ public class AttachmentDatabase extends Database {
values.put(TRANSFER_STATE, TRANSFER_PROGRESS_DONE);
values.put(CONTENT_LOCATION, (String)null);
values.put(CONTENT_DISPOSITION, (String)null);
values.put(DIGEST, (byte[])null);
values.put(NAME, (String) null);
if (database.update(TABLE_NAME, values, PART_ID_WHERE, attachmentId.toStrings()) == 0) {
@ -324,7 +327,8 @@ public class AttachmentDatabase extends Database {
dataSize,
databaseAttachment.getLocation(),
databaseAttachment.getKey(),
databaseAttachment.getRelay());
databaseAttachment.getRelay(),
databaseAttachment.getDigest());
}
@ -446,7 +450,8 @@ public class AttachmentDatabase extends Database {
cursor.getLong(cursor.getColumnIndexOrThrow(SIZE)),
cursor.getString(cursor.getColumnIndexOrThrow(CONTENT_LOCATION)),
cursor.getString(cursor.getColumnIndexOrThrow(CONTENT_DISPOSITION)),
cursor.getString(cursor.getColumnIndexOrThrow(NAME)));
cursor.getString(cursor.getColumnIndexOrThrow(NAME)),
cursor.getBlob(cursor.getColumnIndexOrThrow(DIGEST)));
}
@ -470,6 +475,7 @@ public class AttachmentDatabase extends Database {
contentValues.put(TRANSFER_STATE, attachment.getTransferState());
contentValues.put(UNIQUE_ID, uniqueId);
contentValues.put(CONTENT_LOCATION, attachment.getLocation());
contentValues.put(DIGEST, attachment.getDigest());
contentValues.put(CONTENT_DISPOSITION, attachment.getKey());
contentValues.put(NAME, attachment.getRelay());

View File

@ -74,7 +74,8 @@ public class DatabaseFactory {
private static final int INTRODUCED_SUBSCRIPTION_ID_VERSION = 27;
private static final int INTRODUCED_EXPIRE_MESSAGES_VERSION = 28;
private static final int INTRODUCED_LAST_SEEN = 29;
private static final int DATABASE_VERSION = 29;
private static final int INTRODUCED_DIGEST = 30;
private static final int DATABASE_VERSION = 30;
private static final String DATABASE_NAME = "messages.db";
private static final Object lock = new Object();
@ -835,6 +836,11 @@ public class DatabaseFactory {
db.execSQL("ALTER TABLE thread ADD COLUMN last_seen INTEGER DEFAULT 0");
}
if (oldVersion < INTRODUCED_DIGEST) {
db.execSQL("ALTER TABLE part ADD COLUMN digest BLOB");
db.execSQL("ALTER TABLE groups ADD COLUMN avatar_digest BLOB");
}
db.setTransactionSuccessful();
db.endTransaction();
}

View File

@ -43,6 +43,7 @@ public class GroupDatabase extends Database {
private static final String AVATAR_KEY = "avatar_key";
private static final String AVATAR_CONTENT_TYPE = "avatar_content_type";
private static final String AVATAR_RELAY = "avatar_relay";
private static final String AVATAR_DIGEST = "avatar_digest";
private static final String TIMESTAMP = "timestamp";
private static final String ACTIVE = "active";
@ -58,7 +59,8 @@ public class GroupDatabase extends Database {
AVATAR_CONTENT_TYPE + " TEXT, " +
AVATAR_RELAY + " TEXT, " +
TIMESTAMP + " INTEGER, " +
ACTIVE + " INTEGER DEFAULT 1);";
ACTIVE + " INTEGER DEFAULT 1, " +
AVATAR_DIGEST + " BLOB);";
public static final String[] CREATE_INDEXS = {
"CREATE UNIQUE INDEX IF NOT EXISTS group_id_index ON " + TABLE_NAME + " (" + GROUP_ID + ");",
@ -126,6 +128,7 @@ public class GroupDatabase extends Database {
contentValues.put(AVATAR_ID, avatar.getId());
contentValues.put(AVATAR_KEY, avatar.getKey());
contentValues.put(AVATAR_CONTENT_TYPE, avatar.getContentType());
contentValues.put(AVATAR_DIGEST, avatar.getDigest().orNull());
}
contentValues.put(AVATAR_RELAY, relay);
@ -144,6 +147,7 @@ public class GroupDatabase extends Database {
contentValues.put(AVATAR_ID, avatar.getId());
contentValues.put(AVATAR_CONTENT_TYPE, avatar.getContentType());
contentValues.put(AVATAR_KEY, avatar.getKey());
contentValues.put(AVATAR_DIGEST, avatar.getDigest().orNull());
}
databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues,
@ -269,7 +273,8 @@ public class GroupDatabase extends Database {
cursor.getBlob(cursor.getColumnIndexOrThrow(AVATAR_KEY)),
cursor.getString(cursor.getColumnIndexOrThrow(AVATAR_CONTENT_TYPE)),
cursor.getString(cursor.getColumnIndexOrThrow(AVATAR_RELAY)),
cursor.getInt(cursor.getColumnIndexOrThrow(ACTIVE)) == 1);
cursor.getInt(cursor.getColumnIndexOrThrow(ACTIVE)) == 1,
cursor.getBlob(cursor.getColumnIndexOrThrow(AVATAR_DIGEST)));
}
public void close() {
@ -286,13 +291,14 @@ public class GroupDatabase extends Database {
private final byte[] avatar;
private final long avatarId;
private final byte[] avatarKey;
private final byte[] avatarDigest;
private final String avatarContentType;
private final String relay;
private final boolean active;
public GroupRecord(String id, String title, String members, byte[] avatar,
long avatarId, byte[] avatarKey, String avatarContentType,
String relay, boolean active)
String relay, boolean active, byte[] avatarDigest)
{
this.id = id;
this.title = title;
@ -300,6 +306,7 @@ public class GroupDatabase extends Database {
this.avatar = avatar;
this.avatarId = avatarId;
this.avatarKey = avatarKey;
this.avatarDigest = avatarDigest;
this.avatarContentType = avatarContentType;
this.relay = relay;
this.active = active;
@ -337,6 +344,10 @@ public class GroupDatabase extends Database {
return avatarKey;
}
public byte[] getAvatarDigest() {
return avatarDigest;
}
public String getAvatarContentType() {
return avatarContentType;
}

View File

@ -96,7 +96,7 @@ public class MediaDatabase extends Database {
}
public Attachment getAttachment() {
return new DatabaseAttachment(attachmentId, mmsId, hasData, hasThumbnail, contentType, transferState, size, null, null, null);
return new DatabaseAttachment(attachmentId, mmsId, hasData, hasThumbnail, contentType, transferState, size, null, null, null, null);
}
public String getContentType() {

View File

@ -142,6 +142,7 @@ public class MmsDatabase extends MessagingDatabase {
AttachmentDatabase.THUMBNAIL,
AttachmentDatabase.CONTENT_TYPE,
AttachmentDatabase.CONTENT_LOCATION,
AttachmentDatabase.DIGEST,
AttachmentDatabase.CONTENT_DISPOSITION,
AttachmentDatabase.NAME,
AttachmentDatabase.TRANSFER_STATE
@ -681,7 +682,8 @@ public class MmsDatabase extends MessagingDatabase {
databaseAttachment.getSize(),
databaseAttachment.getLocation(),
databaseAttachment.getKey(),
databaseAttachment.getRelay()));
databaseAttachment.getRelay(),
databaseAttachment.getDigest()));
}
return insertMediaMessage(new MasterSecretUnion(masterSecret),

View File

@ -65,6 +65,7 @@ public class MmsSmsDatabase extends Database {
AttachmentDatabase.THUMBNAIL,
AttachmentDatabase.CONTENT_TYPE,
AttachmentDatabase.CONTENT_LOCATION,
AttachmentDatabase.DIGEST,
AttachmentDatabase.CONTENT_DISPOSITION,
AttachmentDatabase.NAME,
AttachmentDatabase.TRANSFER_STATE};
@ -157,6 +158,7 @@ public class MmsSmsDatabase extends Database {
AttachmentDatabase.THUMBNAIL,
AttachmentDatabase.CONTENT_TYPE,
AttachmentDatabase.CONTENT_LOCATION,
AttachmentDatabase.DIGEST,
AttachmentDatabase.CONTENT_DISPOSITION,
AttachmentDatabase.NAME,
AttachmentDatabase.TRANSFER_STATE};
@ -183,6 +185,7 @@ public class MmsSmsDatabase extends Database {
AttachmentDatabase.THUMBNAIL,
AttachmentDatabase.CONTENT_TYPE,
AttachmentDatabase.CONTENT_LOCATION,
AttachmentDatabase.DIGEST,
AttachmentDatabase.CONTENT_DISPOSITION,
AttachmentDatabase.NAME,
AttachmentDatabase.TRANSFER_STATE};
@ -235,6 +238,7 @@ public class MmsSmsDatabase extends Database {
mmsColumnsPresent.add(AttachmentDatabase.THUMBNAIL);
mmsColumnsPresent.add(AttachmentDatabase.CONTENT_TYPE);
mmsColumnsPresent.add(AttachmentDatabase.CONTENT_LOCATION);
mmsColumnsPresent.add(AttachmentDatabase.DIGEST);
mmsColumnsPresent.add(AttachmentDatabase.CONTENT_DISPOSITION);
mmsColumnsPresent.add(AttachmentDatabase.NAME);
mmsColumnsPresent.add(AttachmentDatabase.TRANSFER_STATE);

View File

@ -19,9 +19,11 @@ import org.thoughtcrime.securesms.events.PartProgressEvent;
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
import org.thoughtcrime.securesms.jobs.requirements.MediaNetworkRequirement;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.util.Hex;
import org.whispersystems.jobqueue.JobParameters;
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
import org.whispersystems.libsignal.InvalidMessageException;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment.ProgressListener;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer;
@ -149,7 +151,13 @@ public class AttachmentDownloadJob extends MasterSecretJob implements Injectable
relay = attachment.getRelay();
}
return new SignalServiceAttachmentPointer(id, null, key, relay);
if (attachment.getDigest() != null) {
Log.w(TAG, "Downloading attachment with digest: " + Hex.toString(attachment.getDigest()));
} else {
Log.w(TAG, "Downloading attachment with no digest...");
}
return new SignalServiceAttachmentPointer(id, null, key, relay, Optional.fromNullable(attachment.getDigest()));
} catch (InvalidMessageException | IOException e) {
Log.w(TAG, e);
throw new InvalidPartException(e);

View File

@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.jobs;
import android.content.Context;
import android.graphics.Bitmap;
import android.support.annotation.NonNull;
import android.util.Log;
import org.thoughtcrime.securesms.crypto.MasterSecret;
@ -12,9 +13,11 @@ import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
import org.thoughtcrime.securesms.mms.AttachmentStreamUriLoader.AttachmentModel;
import org.thoughtcrime.securesms.util.BitmapDecodingException;
import org.thoughtcrime.securesms.util.BitmapUtil;
import org.thoughtcrime.securesms.util.Hex;
import org.whispersystems.jobqueue.JobParameters;
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
import org.whispersystems.libsignal.InvalidMessageException;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer;
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException;
@ -35,7 +38,7 @@ public class AvatarDownloadJob extends MasterSecretJob implements InjectableType
private final byte[] groupId;
public AvatarDownloadJob(Context context, byte[] groupId) {
public AvatarDownloadJob(Context context, @NonNull byte[] groupId) {
super(context, JobParameters.newBuilder()
.withRequirement(new MasterSecretRequirement(context))
.withRequirement(new NetworkRequirement(context))
@ -60,17 +63,20 @@ public class AvatarDownloadJob extends MasterSecretJob implements InjectableType
String contentType = record.getAvatarContentType();
byte[] key = record.getAvatarKey();
String relay = record.getRelay();
Optional<byte[]> digest = Optional.fromNullable(record.getAvatarDigest());
if (avatarId == -1 || key == null) {
return;
}
if (digest.isPresent()) {
Log.w(TAG, "Downloading group avatar with digest: " + Hex.toString(digest.get()));
}
attachment = File.createTempFile("avatar", "tmp", context.getCacheDir());
attachment.deleteOnExit();
SignalServiceAttachmentPointer pointer = new SignalServiceAttachmentPointer(avatarId, contentType, key, relay);
SignalServiceAttachmentPointer pointer = new SignalServiceAttachmentPointer(avatarId, contentType, key, relay, digest);
InputStream inputStream = receiver.retrieveAttachment(pointer, attachment);
Bitmap avatar = BitmapUtil.createScaledBitmap(context, new AttachmentModel(attachment, key), 500, 500);

View File

@ -10,6 +10,7 @@ import com.bumptech.glide.load.data.DataFetcher;
import com.bumptech.glide.load.data.StreamLocalUriFetcher;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.crypto.AttachmentCipherInputStream;
import java.io.File;
@ -29,7 +30,7 @@ public class AttachmentStreamLocalUriFetcher implements DataFetcher<InputStream>
}
@Override public InputStream loadData(Priority priority) throws Exception {
is = new AttachmentCipherInputStream(attachment, key);
is = new AttachmentCipherInputStream(attachment, key, Optional.<byte[]>absent());
return is;
}