use FileHelper.openOutputStreamSafe to resolve output streams
This commit is contained in:
@@ -32,9 +32,9 @@ import java.util.regex.Pattern;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.bouncycastle.bcpg.ArmoredOutputStream;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
@@ -113,12 +113,12 @@ public class BackupOperation extends BaseOperation<BackupKeyringParcel> {
|
||||
}
|
||||
|
||||
plainUri = TemporaryFileProvider.createFile(mContext);
|
||||
plainOut = mContext.getContentResolver().openOutputStream(plainUri);
|
||||
plainOut = FileHelper.openOutputStreamSafe(mContext.getContentResolver(), plainUri);
|
||||
} else {
|
||||
if (backupInput.getOutputUri() == null || outputStream != null) {
|
||||
throw new IllegalArgumentException("Unencrypted export to output stream is not supported!");
|
||||
} else {
|
||||
plainOut = mContext.getContentResolver().openOutputStream(backupInput.getOutputUri());
|
||||
plainOut = FileHelper.openOutputStreamSafe(mContext.getContentResolver(), backupInput.getOutputUri());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,7 +201,7 @@ public class BackupOperation extends BaseOperation<BackupKeyringParcel> {
|
||||
if (outputStream != null) {
|
||||
throw new IllegalArgumentException("If output uri is set, outputStream must null!");
|
||||
}
|
||||
outStream = mContext.getContentResolver().openOutputStream(backupInput.getOutputUri());
|
||||
outStream = FileHelper.openOutputStreamSafe(mContext.getContentResolver(), backupInput.getOutputUri());
|
||||
}
|
||||
|
||||
return signEncryptOperation.execute(
|
||||
|
||||
@@ -33,10 +33,10 @@ import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
import android.text.TextUtils;
|
||||
import android.webkit.MimeTypeMap;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import org.bouncycastle.bcpg.ArmoredInputStream;
|
||||
import org.bouncycastle.openpgp.PGPCompressedData;
|
||||
import org.bouncycastle.openpgp.PGPDataValidationException;
|
||||
@@ -61,6 +61,8 @@ import org.openintents.openpgp.OpenPgpMetadata;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.Constants.key;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
||||
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
|
||||
import org.sufficientlysecure.keychain.operations.BaseOperation;
|
||||
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
|
||||
@@ -71,8 +73,6 @@ import org.sufficientlysecure.keychain.pgp.SecurityProblem.EncryptionAlgorithmPr
|
||||
import org.sufficientlysecure.keychain.pgp.SecurityProblem.KeySecurityProblem;
|
||||
import org.sufficientlysecure.keychain.pgp.SecurityProblem.MissingMdc;
|
||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
||||
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
|
||||
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
||||
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
|
||||
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.RequireAnyDecryptPassphraseBuilder;
|
||||
@@ -129,7 +129,7 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
|
||||
outputStream = new ByteArrayOutputStream();
|
||||
} else {
|
||||
try {
|
||||
outputStream = mContext.getContentResolver().openOutputStream(input.getOutputUri());
|
||||
outputStream = FileHelper.openOutputStreamSafe(mContext.getContentResolver(), input.getOutputUri());
|
||||
} catch (FileNotFoundException e) {
|
||||
Timber.e(e, "Output URI could not be opened: " + input.getOutputUri());
|
||||
OperationLog log = new OperationLog();
|
||||
|
||||
@@ -37,8 +37,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import org.bouncycastle.bcpg.ArmoredOutputStream;
|
||||
import org.bouncycastle.bcpg.BCPGOutputStream;
|
||||
import org.bouncycastle.bcpg.CompressionAlgorithmTags;
|
||||
@@ -143,7 +143,7 @@ public class PgpSignEncryptOperation extends BaseOperation<PgpSignEncryptInputPa
|
||||
if (input.getOutputUri() != null) {
|
||||
try {
|
||||
Uri outputUri = input.getOutputUri();
|
||||
outStream = mContext.getContentResolver().openOutputStream(outputUri);
|
||||
outStream = FileHelper.openOutputStreamSafe(mContext.getContentResolver(), outputUri);
|
||||
} catch (FileNotFoundException e) {
|
||||
log.add(LogType.MSG_PSE_ERROR_OUTPUT_URI_NOT_FOUND, 1);
|
||||
return new PgpSignEncryptResult(SignEncryptResult.RESULT_ERROR, log);
|
||||
|
||||
@@ -24,21 +24,20 @@ import java.util.ArrayList;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpHelper;
|
||||
import org.sufficientlysecure.keychain.provider.TemporaryFileProvider;
|
||||
import org.sufficientlysecure.keychain.ui.base.BaseActivity;
|
||||
import org.sufficientlysecure.keychain.util.FileHelper;
|
||||
|
||||
|
||||
public class DecryptActivity extends BaseActivity {
|
||||
@@ -200,7 +199,7 @@ public class DecryptActivity extends BaseActivity {
|
||||
@Nullable
|
||||
public Uri readToTempFile(String text) throws IOException {
|
||||
Uri tempFile = TemporaryFileProvider.createFile(this);
|
||||
OutputStream outStream = getContentResolver().openOutputStream(tempFile);
|
||||
OutputStream outStream = FileHelper.openOutputStreamSafe(getContentResolver(), tempFile);
|
||||
if (outStream == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -44,11 +44,6 @@ import android.os.Build;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
@@ -65,8 +60,12 @@ import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import android.widget.ViewAnimator;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.cocosw.bottomsheet.BottomSheet;
|
||||
|
||||
import org.openintents.openpgp.OpenPgpMetadata;
|
||||
import org.openintents.openpgp.OpenPgpSignatureResult;
|
||||
import org.sufficientlysecure.keychain.BuildConfig;
|
||||
@@ -79,16 +78,15 @@ import org.sufficientlysecure.keychain.operations.results.InputDataResult;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
|
||||
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
|
||||
import org.sufficientlysecure.keychain.service.InputDataParcel;
|
||||
import org.sufficientlysecure.keychain.ui.DecryptListFragment.DecryptFilesAdapter.ViewModel;
|
||||
import org.sufficientlysecure.keychain.ui.DecryptListFragment.ViewHolder.SubViewHolder;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.SpacesItemDecoration;
|
||||
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
|
||||
import org.sufficientlysecure.keychain.ui.base.QueueingCryptoOperationFragment;
|
||||
// this import NEEDS to be above the ViewModel AND SubViewHolder one, or it won't compile! (as of 16.09.15)
|
||||
import org.sufficientlysecure.keychain.ui.keyview.ViewKeyActivity;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.StatusHolder;
|
||||
import org.sufficientlysecure.keychain.ui.DecryptListFragment.ViewHolder.SubViewHolder;
|
||||
import org.sufficientlysecure.keychain.ui.DecryptListFragment.DecryptFilesAdapter.ViewModel;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.SpacesItemDecoration;
|
||||
import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.StatusHolder;
|
||||
import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
|
||||
import org.sufficientlysecure.keychain.util.FileHelper;
|
||||
|
||||
@@ -25,11 +25,11 @@ import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.SubLogEntryParcel;
|
||||
@@ -39,6 +39,7 @@ import org.sufficientlysecure.keychain.ui.base.RecyclerFragment;
|
||||
import org.sufficientlysecure.keychain.ui.dialog.ShareLogDialogFragment;
|
||||
import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
|
||||
import org.sufficientlysecure.keychain.util.FileHelper;
|
||||
|
||||
|
||||
public class LogDisplayFragment extends RecyclerFragment<NestedLogAdapter>
|
||||
@@ -120,15 +121,15 @@ public class LogDisplayFragment extends RecyclerFragment<NestedLogAdapter>
|
||||
if (mLogTempFile == null) {
|
||||
mLogTempFile = TemporaryFileProvider.createFile(getActivity(), "openkeychain_log.txt", "text/plain");
|
||||
try {
|
||||
OutputStream outputStream = activity.getContentResolver().openOutputStream(mLogTempFile);
|
||||
OutputStream outputStream = FileHelper.openOutputStreamSafe(activity.getContentResolver(), mLogTempFile);
|
||||
outputStream.write(log.getBytes());
|
||||
outputStream.close();
|
||||
} catch (IOException | NullPointerException e) {
|
||||
Notify.create(activity, R.string.error_log_share_internal, Style.ERROR).show();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ShareLogDialogFragment shareLogDialog = ShareLogDialogFragment.newInstance(mLogTempFile);
|
||||
shareLogDialog.show(getActivity().getSupportFragmentManager(), "shareLogDialog");
|
||||
}
|
||||
|
||||
@@ -299,7 +299,7 @@ public class FileHelper {
|
||||
try {
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
bis = new BufferedInputStream(FileHelper.openInputStreamSafe(resolver, fromUri));
|
||||
bos = new BufferedOutputStream(resolver.openOutputStream(toUri));
|
||||
bos = new BufferedOutputStream(FileHelper.openOutputStreamSafe(resolver, toUri));
|
||||
byte[] buf = new byte[1024];
|
||||
int len;
|
||||
while ( (len = bis.read(buf)) > 0) {
|
||||
@@ -388,4 +388,14 @@ public class FileHelper {
|
||||
}
|
||||
}
|
||||
|
||||
public static OutputStream openOutputStreamSafe(ContentResolver resolver, Uri uri)
|
||||
throws FileNotFoundException {
|
||||
|
||||
// Not supported on Android < 5
|
||||
if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
|
||||
return FileHelperLollipop.openOutputStreamSafe(resolver, uri);
|
||||
} else {
|
||||
return resolver.openOutputStream(uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
@@ -88,4 +89,35 @@ class FileHelperLollipop {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static OutputStream openOutputStreamSafe(ContentResolver resolver, Uri uri)
|
||||
throws FileNotFoundException {
|
||||
|
||||
String scheme = uri.getScheme();
|
||||
if (ContentResolver.SCHEME_FILE.equals(scheme)) {
|
||||
ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
|
||||
new File(uri.getPath()), ParcelFileDescriptor.parseMode("w"));
|
||||
|
||||
try {
|
||||
final StructStat st = Os.fstat(pfd.getFileDescriptor());
|
||||
if (st.st_uid == android.os.Process.myUid()) {
|
||||
Timber.e("File is owned by the application itself, aborting!");
|
||||
throw new FileNotFoundException("Unable to create stream");
|
||||
}
|
||||
} catch (ErrnoException e) {
|
||||
Timber.e(e, "fstat() failed");
|
||||
throw new FileNotFoundException("fstat() failed");
|
||||
}
|
||||
|
||||
AssetFileDescriptor fd = new AssetFileDescriptor(pfd, 0, -1);
|
||||
try {
|
||||
return fd.createOutputStream();
|
||||
} catch (IOException e) {
|
||||
throw new FileNotFoundException("Unable to create stream");
|
||||
}
|
||||
} else {
|
||||
return resolver.openOutputStream(uri);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user