mirror of
https://github.com/oxen-io/session-android.git
synced 2025-10-25 05:39:18 +00:00
committed by
Moxie Marlinspike
parent
60ab71099f
commit
59f2446a2b
@@ -6,7 +6,6 @@ import android.content.UriMatcher;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.util.SparseArrayCompat;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.DecryptingPartInputStream;
|
||||
@@ -21,25 +20,27 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class CaptureProvider {
|
||||
private static final String TAG = CaptureProvider.class.getSimpleName();
|
||||
private static final String URI_STRING = "content://org.thoughtcrime.securesms/capture";
|
||||
public static final Uri CONTENT_URI = Uri.parse(URI_STRING);
|
||||
public static final String AUTHORITY = "org.thoughtcrime.securesms";
|
||||
public static final String EXPECTED_PATH = "capture/*/#";
|
||||
private static final int MATCH = 1;
|
||||
public static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH) {{
|
||||
public class PersistentBlobProvider {
|
||||
private static final String TAG = PersistentBlobProvider.class.getSimpleName();
|
||||
private static final String URI_STRING = "content://org.thoughtcrime.securesms/capture";
|
||||
public static final Uri CONTENT_URI = Uri.parse(URI_STRING);
|
||||
public static final String AUTHORITY = "org.thoughtcrime.securesms";
|
||||
public static final String EXPECTED_PATH = "capture/*/#";
|
||||
private static final int MATCH = 1;
|
||||
private static final UriMatcher MATCHER = new UriMatcher(UriMatcher.NO_MATCH) {{
|
||||
addURI(AUTHORITY, EXPECTED_PATH, MATCH);
|
||||
}};
|
||||
|
||||
private static volatile CaptureProvider instance;
|
||||
private static volatile PersistentBlobProvider instance;
|
||||
|
||||
public static CaptureProvider getInstance(Context context) {
|
||||
public static PersistentBlobProvider getInstance(Context context) {
|
||||
if (instance == null) {
|
||||
synchronized (CaptureProvider.class) {
|
||||
synchronized (PersistentBlobProvider.class) {
|
||||
if (instance == null) {
|
||||
instance = new CaptureProvider(context);
|
||||
instance = new PersistentBlobProvider(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,9 +48,9 @@ public class CaptureProvider {
|
||||
}
|
||||
|
||||
private final Context context;
|
||||
private final SparseArrayCompat<byte[]> cache = new SparseArrayCompat<>();
|
||||
private final Map<Long, byte[]> cache = new HashMap<>();
|
||||
|
||||
private CaptureProvider(Context context) {
|
||||
private PersistentBlobProvider(Context context) {
|
||||
this.context = context.getApplicationContext();
|
||||
}
|
||||
|
||||
@@ -57,19 +58,31 @@ public class CaptureProvider {
|
||||
@NonNull Recipients recipients,
|
||||
@NonNull byte[] imageBytes)
|
||||
{
|
||||
final int id = generateId(recipients);
|
||||
final long id = generateId(recipients);
|
||||
cache.put(id, imageBytes);
|
||||
persistToDisk(masterSecret, id, imageBytes);
|
||||
return create(masterSecret, new ByteArrayInputStream(imageBytes), id);
|
||||
}
|
||||
|
||||
public Uri create(@NonNull MasterSecret masterSecret,
|
||||
@NonNull InputStream input)
|
||||
{
|
||||
return create(masterSecret, input, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
private Uri create(MasterSecret masterSecret, InputStream input, long id) {
|
||||
persistToDisk(masterSecret, id, input);
|
||||
final Uri uniqueUri = Uri.withAppendedPath(CONTENT_URI, String.valueOf(System.currentTimeMillis()));
|
||||
return ContentUris.withAppendedId(uniqueUri, id);
|
||||
}
|
||||
|
||||
private void persistToDisk(final MasterSecret masterSecret, final int id, final byte[] imageBytes) {
|
||||
private void persistToDisk(final MasterSecret masterSecret, final long id,
|
||||
final InputStream input)
|
||||
{
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@Override protected Void doInBackground(Void... params) {
|
||||
try {
|
||||
final OutputStream output = new EncryptingPartOutputStream(getFile(id), masterSecret);
|
||||
Util.copy(new ByteArrayInputStream(imageBytes), output);
|
||||
Util.copy(input, output);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
@@ -83,23 +96,21 @@ public class CaptureProvider {
|
||||
}
|
||||
|
||||
public Uri createForExternal(@NonNull Recipients recipients) throws IOException {
|
||||
final File externalDir = context.getExternalFilesDir(null);
|
||||
if (externalDir == null) throw new IOException("no external files directory");
|
||||
return Uri.fromFile(new File(externalDir, String.valueOf(generateId(recipients)) + ".jpg"))
|
||||
return Uri.fromFile(new File(getExternalDir(context), String.valueOf(generateId(recipients)) + ".jpg"))
|
||||
.buildUpon()
|
||||
.appendQueryParameter("unique", String.valueOf(System.currentTimeMillis()))
|
||||
.build();
|
||||
}
|
||||
|
||||
public boolean delete(@NonNull Uri uri) {
|
||||
switch (uriMatcher.match(uri)) {
|
||||
switch (MATCHER.match(uri)) {
|
||||
case MATCH: return getFile(ContentUris.parseId(uri)).delete();
|
||||
default: return new File(uri.getPath()).delete();
|
||||
}
|
||||
}
|
||||
|
||||
public @NonNull InputStream getStream(MasterSecret masterSecret, long id) throws IOException {
|
||||
final byte[] cached = cache.get((int)id);
|
||||
final byte[] cached = cache.get(id);
|
||||
return cached != null ? new ByteArrayInputStream(cached)
|
||||
: new DecryptingPartInputStream(getFile(id), masterSecret);
|
||||
}
|
||||
@@ -111,4 +122,18 @@ public class CaptureProvider {
|
||||
private File getFile(long id) {
|
||||
return new File(context.getDir("captures", Context.MODE_PRIVATE), id + ".jpg");
|
||||
}
|
||||
|
||||
private static @NonNull File getExternalDir(Context context) throws IOException {
|
||||
final File externalDir = context.getExternalFilesDir(null);
|
||||
if (externalDir == null) throw new IOException("no external files directory");
|
||||
return externalDir;
|
||||
}
|
||||
|
||||
public static boolean isAuthority(@NonNull Context context, @NonNull Uri uri) {
|
||||
try {
|
||||
return MATCHER.match(uri) == MATCH || uri.getPath().startsWith(getExternalDir(context).getAbsolutePath());
|
||||
} catch (IOException ioe) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ import java.util.Map;
|
||||
|
||||
public class SingleUseBlobProvider {
|
||||
|
||||
private static final String TAG = CaptureProvider.class.getSimpleName();
|
||||
private static final String TAG = SingleUseBlobProvider.class.getSimpleName();
|
||||
|
||||
public static final String AUTHORITY = "org.thoughtcrime.securesms";
|
||||
public static final String PATH = "memory/*/#";
|
||||
|
||||
Reference in New Issue
Block a user