com.osama.cryptofm.tasks.DecryptTask.java Source code

Java tutorial

Introduction

Here is the source code for com.osama.cryptofm.tasks.DecryptTask.java

Source

/*
 * Copyright (c) 2017. Osama Bin Omar
 *    This file is part of Crypto File Manager also known as Crypto FM
 *
 *     Crypto File Manager is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     Crypto File Manager is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with Crypto File Manager.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package com.osama.cryptofm.tasks;

import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Environment;
import android.support.v4.content.FileProvider;
import android.support.v4.provider.DocumentFile;
import android.util.Log;
import android.webkit.MimeTypeMap;
import android.widget.Toast;

import com.osama.cryptofm.CryptoFM;
import com.osama.cryptofm.encryption.DatabaseHandler;
import com.osama.cryptofm.encryption.DocumentFileEncryption;
import com.osama.cryptofm.encryption.EncryptionWrapper;
import com.osama.cryptofm.filemanager.listview.FileListAdapter;
import com.osama.cryptofm.filemanager.utils.SharedData;
import com.osama.cryptofm.filemanager.utils.UiUtils;
import com.osama.cryptofm.utils.FileDocumentUtils;
import com.osama.cryptofm.utils.FileUtils;

import net.sqlcipher.database.SQLiteDatabase;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;

/**
 * Created by tripleheader on 1/2/17.
 * file decryption task
 */

public class DecryptTask extends AsyncTask<Void, String, String> {
    private ArrayList<String> mFilePaths;
    private FileListAdapter mAdapter;
    private MyProgressDialog mProgressDialog;
    private Context mContext;
    private InputStream mSecKey;
    private String mDbPassword;
    private String mUsername;
    private String mFileName = null;
    private File mPubKey;
    private char[] mKeyPass;
    private String rootPath;
    private ProgressDialog singleModeDialog;
    private String destFilename;

    private ArrayList<File> mCreatedFiles = new ArrayList<>();
    private boolean singleFileMode = false;

    private static final String TAG = DecryptTask.class.getName();
    private static final String DECRYPTION_SUCCESS_MESSAGE = "Decryption successful";

    public DecryptTask(Context context, FileListAdapter adapter, ArrayList<String> filePaths, String DbPass,
            String mUsername, String keypass) {
        this.mContext = context;
        this.mAdapter = adapter;
        this.mFilePaths = filePaths;
        this.mUsername = mUsername;
        this.mKeyPass = keypass.toCharArray();
        this.mDbPassword = DbPass;
        this.mSecKey = getSecretKey();
        this.mProgressDialog = new MyProgressDialog(mContext, "Decrypting", this);
        this.mPubKey = new File(mContext.getFilesDir(), "pub.asc");

    }

    public DecryptTask(Context context, FileListAdapter adapter, String DbPass, String mUsername, String filename,
            String keypass) {
        this.mContext = context;
        this.mAdapter = adapter;
        this.mFileName = filename;
        this.mDbPassword = DbPass;
        this.mKeyPass = keypass.toCharArray();
        this.mUsername = mUsername;
        this.mSecKey = getSecretKey();
        this.singleModeDialog = new ProgressDialog(mContext);
        this.singleFileMode = true;

    }

    @Override
    protected String doInBackground(Void... voids) {

        try {
            File root = new File(Environment.getExternalStorageDirectory(), "decrypted");
            if (!root.exists()) {
                if (!root.mkdir()) {
                    return "cannot decrypt file";
                }
            }
            rootPath = root.getPath();

            if (mFileName == null) {
                //check if files are from external storage
                if (FileUtils.isDocumentFile(mFilePaths.get(0))) {
                    //do the document files decryption
                    performDocumentFileDecryption();
                } else {
                    //do the normal files decryption
                    performNormalFormDecryption();
                }

            } else {
                File in = TasksFileUtils.getFile(mFileName);
                File out = TasksFileUtils
                        .getFile(root.getPath() + "/" + in.getName().substring(0, in.getName().lastIndexOf('.')));
                destFilename = out.getAbsolutePath();
                mSecKey = getSecretKey();
                EncryptionWrapper.decryptFile(in, out, mPubKey, getSecretKey(), mKeyPass);
            }

        } catch (Exception ex) {
            //let the activity know that password is incorrect and don't save it
            SharedData.KEY_PASSWORD = null;
            ex.printStackTrace();
            return ex.getMessage();
        }

        return DECRYPTION_SUCCESS_MESSAGE;
    }

    private ArrayList<String> tmp = new ArrayList<>();

    private ArrayList<String> getOnlyEncryptedFiles(ArrayList<String> mFilePaths) throws IOException {
        int size = mFilePaths.size();
        for (int i = 0; i < size; i++) {
            Log.d(TAG, "getOnlyEncryptedFiles: file path is: " + mFilePaths.get(i));
            File f = TasksFileUtils.getFile(mFilePaths.get(i));
            if (f.isDirectory()) {
                File[] fs = f.listFiles();
                ArrayList<String> tmp1 = new ArrayList<>();
                for (File fin : fs) {
                    tmp1.add(fin.getAbsolutePath());
                }
                getOnlyEncryptedFiles(tmp1);
            }
            if (FileUtils.isEncryptedFile(mFilePaths.get(i))) {
                tmp.add(mFilePaths.get(i));
            }
        }
        if (tmp.size() < 1) {
            throw new IllegalArgumentException("No encrypted files found");
        }
        return tmp;
    }

    private void decryptFile(File f) throws Exception {
        Log.d(TAG, "decryptFile: task is running");
        if (!isCancelled()) {
            if (f.isDirectory()) {
                for (File tmp : f.listFiles()) {
                    decryptFile(tmp);
                }
            } else {
                File out = new File(rootPath + "/", f.getName().substring(0, f.getName().lastIndexOf('.')));
                if (out.exists()) {
                    if (!out.delete()) {
                        throw new IOException("Error in deleting already present file");
                    }
                }

                publishProgress(f.getName(), "" + ((FileUtils.getReadableSize((f.length())))));
                mCreatedFiles.add(out);
                if (!EncryptionWrapper.decryptFile(f, out, mPubKey, getSecretKey(), mKeyPass)) {
                    if (out.delete()) {
                        throw new Exception("Error in decrypting file");
                    }
                }
            }
        }

    }

    private InputStream getSecretKey() {
        SQLiteDatabase.loadLibs(mContext);
        DatabaseHandler handler = new DatabaseHandler(mContext, mDbPassword, true);
        try {
            mSecKey = new BufferedInputStream(new ByteArrayInputStream(handler.getSecretKeyFromDb(mUsername)));
        } catch (Exception e) {
            e.printStackTrace();
        }
        assert mSecKey != null;
        return mSecKey;
    }

    @Override
    protected void onPostExecute(String s) {
        SharedData.CURRENT_RUNNING_OPERATIONS.clear();

        if (singleFileMode) {
            if (s.equals(DECRYPTION_SUCCESS_MESSAGE)) {
                singleModeDialog.dismiss();
                Log.d(TAG, "onPostExecute: destination filename is: " + destFilename);
                //open file
                String mimeType = MimeTypeMap.getSingleton()
                        .getMimeTypeFromExtension(FileUtils.getExtension(destFilename));

                Intent intent = new Intent();
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

                    Uri uri = null;
                    try {
                        uri = FileProvider.getUriForFile(mContext,
                                mContext.getApplicationContext().getPackageName() + ".provider",
                                TasksFileUtils.getFile(destFilename));
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    intent.setDataAndType(uri, mimeType);
                } else {
                    try {
                        intent.setDataAndType(Uri.fromFile(TasksFileUtils.getFile(destFilename)), mimeType);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                intent.setAction(Intent.ACTION_VIEW);
                Intent x = Intent.createChooser(intent, "Open with: ");
                mContext.startActivity(x);
            } else {
                singleModeDialog.dismiss();
                Toast.makeText(mContext, s, Toast.LENGTH_LONG).show();
            }
        } else {
            mProgressDialog.dismiss("Decryption completed");
            SharedData.CURRENT_RUNNING_OPERATIONS.clear();
            Toast.makeText(mContext, s, Toast.LENGTH_LONG).show();
            UiUtils.reloadData(mContext, mAdapter);
        }

    }

    @Override
    protected void onProgressUpdate(String... values) {
        if (singleFileMode) {
            return;
        }
        mProgressDialog.setmProgressTextViewText(values[0]);
    }

    @Override
    protected void onPreExecute() {
        if (singleFileMode) {
            singleModeDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
            singleModeDialog.setTitle("Decrypting file");
            singleModeDialog.setMessage("Please wait while I finish decrypting file");
            singleModeDialog.setIndeterminate(true);
            singleModeDialog.show();
            return;
        }
        mProgressDialog.show();
    }

    @Override
    protected void onCancelled() {

        for (File f : mCreatedFiles) {
            if (SharedData.EXTERNAL_SDCARD_ROOT_PATH != null
                    && f.getAbsolutePath().contains(SharedData.EXTERNAL_SDCARD_ROOT_PATH)) {
                //noinspection ConstantConditions
                FileDocumentUtils.getDocumentFile(f).delete();
            } else {
                //noinspection ResultOfMethodCallIgnored
                f.delete();
            }
        }

        SharedData.CURRENT_RUNNING_OPERATIONS.clear();
        UiUtils.reloadData(mContext, mAdapter);

        Toast.makeText(mContext, "Operation canceled", Toast.LENGTH_SHORT).show();

        mProgressDialog.dismiss("Canceled");
        super.onCancelled();

    }

    private void performDocumentFileDecryption() throws Exception {
        tmp.clear();
        mFilePaths = getOnlyEncryptedDocumentFiles(mFilePaths);
        for (String path : mFilePaths) {
            decryptDocumentFiles(FileDocumentUtils.getDocumentFile(new File(path)));
        }
    }

    private void decryptDocumentFiles(DocumentFile f) throws Exception {
        Log.d(TAG, "decryptDocumentFiles: Running decryption on document file");
        //first always check if task is canceled
        if (!isCancelled()) {
            if (f.isDirectory()) {
                for (DocumentFile tmpFile : f.listFiles()) {
                    decryptDocumentFiles(tmpFile);
                }
            } else {
                File out = new File(rootPath + "/", f.getName().substring(0, f.getName().lastIndexOf('.')));
                // add the file in created files. top remove the files later of user cancels the task
                mCreatedFiles.add(out.getAbsoluteFile());
                publishProgress(f.getName(), "" + ((FileUtils.getReadableSize((f.length())))));

                DocumentFileEncryption.decryptFile(
                        CryptoFM.getContext().getContentResolver().openInputStream(f.getUri()), getSecretKey(),
                        mKeyPass, new BufferedOutputStream(new FileOutputStream(out))

                );

            }
        }
    }

    private ArrayList<String> getOnlyEncryptedDocumentFiles(ArrayList<String> files) {
        int size = files.size();
        for (int i = 0; i < size; i++) {
            DocumentFile file = FileDocumentUtils.getDocumentFile(new File(files.get(i)));
            //check if file is directory
            assert file != null;
            if (file.isDirectory()) {
                //get all the lists of files in directory
                ArrayList<String> tmp = new ArrayList<>();
                for (DocumentFile f : file.listFiles()) {
                    tmp.add(FileUtils.CURRENT_PATH + f.getName());
                }
                //recursively get files
                getOnlyEncryptedDocumentFiles(tmp);
            }
            if (FileUtils.isEncryptedFile(mFilePaths.get(i))) {
                tmp.add(mFilePaths.get(i));
            }
        }
        //if there are no encrypted file
        if (tmp.size() < 1) {
            throw new IllegalArgumentException("No encrypted files found.");
        }
        return tmp;
    }

    private void performNormalFormDecryption() throws Exception {
        tmp.clear();
        //refactor list to hold only encrypted files
        mFilePaths = getOnlyEncryptedFiles(mFilePaths);
        for (String s : mFilePaths) {
            if (!isCancelled()) {
                Log.d(TAG, "doInBackground: +" + mFilePaths.size());
                File f = TasksFileUtils.getFile(s);
                decryptFile(f);
            }
        }
    }
}