app/src/main/java/swati4star/createpdf/util/PDFEncryptionUtility.java
package swati4star.createpdf.util;
import static swati4star.createpdf.util.Constants.MASTER_PWD_STRING;
import static swati4star.createpdf.util.Constants.appName;
import android.app.Activity;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.text.Editable;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import com.afollestad.materialdialogs.DialogAction;
import com.afollestad.materialdialogs.MaterialDialog;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.PdfWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;
import swati4star.createpdf.R;
import swati4star.createpdf.database.DatabaseHelper;
import swati4star.createpdf.interfaces.DataSetChanged;
public class PDFEncryptionUtility {
private final Activity mContext;
private final FileUtils mFileUtils;
private final MaterialDialog mDialog;
private final SharedPreferences mSharedPrefs;
private String mPassword;
public PDFEncryptionUtility(Activity context) {
this.mContext = context;
this.mFileUtils = new FileUtils(context);
mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
mDialog = new MaterialDialog.Builder(mContext)
.customView(R.layout.custom_dialog, true)
.positiveText(android.R.string.ok)
.negativeText(android.R.string.cancel)
.build();
}
/**
* Opens the password mDialog to set Password for an existing PDF file.
*
* @param filePath Path of file to be encrypted
*/
public void setPassword(final String filePath, final DataSetChanged dataSetChanged) {
mDialog.setTitle(R.string.set_password);
final View mPositiveAction = mDialog.getActionButton(DialogAction.POSITIVE);
assert mDialog.getCustomView() != null;
EditText mPasswordInput = mDialog.getCustomView().findViewById(R.id.password);
mPasswordInput.addTextChangedListener(
new DefaultTextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
mPositiveAction.setEnabled(s.toString().trim().length() > 0);
}
@Override
public void afterTextChanged(Editable input) {
if (StringUtils.getInstance().isEmpty(input))
StringUtils.getInstance().
showSnackbar(mContext, R.string.snackbar_password_cannot_be_blank);
else
mPassword = input.toString();
}
});
mDialog.show();
mPositiveAction.setEnabled(false);
mPositiveAction.setOnClickListener(v -> {
try {
String path = doEncryption(filePath, mPassword);
StringUtils.getInstance().getSnackbarwithAction(mContext, R.string.snackbar_pdfCreated)
.setAction(R.string.snackbar_viewAction, v2 ->
mFileUtils.openFile(path, FileUtils.FileType.e_PDF)).show();
if (dataSetChanged != null)
dataSetChanged.updateDataset();
} catch (IOException | DocumentException e) {
e.printStackTrace();
StringUtils.getInstance().showSnackbar(mContext, R.string.cannot_add_password);
}
mDialog.dismiss();
});
}
/**
* Uses PDF Reader to set encryption in pdf file.
*
* @param path - Path of pdf file to be encrypted
* @param password - password to be encrypted with
* @return string - path of output file
*/
private String doEncryption(String path, String password) throws IOException, DocumentException {
String masterpwd = mSharedPrefs.getString(MASTER_PWD_STRING, appName);
String finalOutputFile = mFileUtils.getUniqueFileName(path.replace(mContext.getString(R.string.pdf_ext),
mContext.getString(R.string.encrypted_file)));
PdfReader reader = new PdfReader(path);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(finalOutputFile));
stamper.setEncryption(password.getBytes(), masterpwd.getBytes(),
PdfWriter.ALLOW_PRINTING | PdfWriter.ALLOW_COPY, PdfWriter.ENCRYPTION_AES_128);
stamper.close();
reader.close();
new DatabaseHelper(mContext).insertRecord(finalOutputFile, mContext.getString(R.string.encrypted));
return finalOutputFile;
}
/**
* Checks if PDf is encrypted
*
* @param file - path of PDF file
* @return true, if PDF is encrypted, otherwise false
*/
private boolean isPDFEncrypted(final String file) {
PdfReader reader;
String ownerPass = mContext.getString(R.string.app_name);
try {
reader = new PdfReader(file, ownerPass.getBytes());
} catch (IOException e) {
e.printStackTrace();
return true;
}
//Check if PDF is encrypted or not.
if (!reader.isEncrypted()) {
StringUtils.getInstance().showSnackbar(mContext, R.string.not_encrypted);
return false;
}
return true;
}
/**
* Uses PDF Reader to decrypt the PDF.
*
* @param file Path of pdf file to be decrypted
*/
public void removePassword(final String file,
final DataSetChanged dataSetChanged) {
if (!isPDFEncrypted(file))
return;
final String[] input_password = new String[1];
mDialog.setTitle(R.string.enter_password);
final View mPositiveAction = mDialog.getActionButton(DialogAction.POSITIVE);
final EditText mPasswordInput = Objects.requireNonNull(mDialog.getCustomView()).findViewById(R.id.password);
TextView text = mDialog.getCustomView().findViewById(R.id.enter_password);
text.setText(R.string.decrypt_message);
mPasswordInput.addTextChangedListener(
new DefaultTextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
mPositiveAction.setEnabled(s.toString().trim().length() > 0);
}
@Override
public void afterTextChanged(Editable input) {
input_password[0] = input.toString();
}
});
mDialog.show();
mPositiveAction.setEnabled(false);
mPositiveAction.setOnClickListener(v -> {
// check for password
// our master password & their user password
// their master password
if (!removePasswordUsingDefMasterPassword(file, dataSetChanged, input_password)) {
if (!removePasswordUsingInputMasterPassword(file, dataSetChanged, input_password)) {
StringUtils.getInstance().showSnackbar(mContext, R.string.master_password_changed);
}
}
mDialog.dismiss();
});
}
/**
* This function removes the password for encrypted files.
*
* @param file - the path of the actual encrypted file.
* @param inputPassword - the password of the encrypted file.
* @return - output file path
*/
public String removeDefPasswordForImages(final String file,
final String[] inputPassword) {
String finalOutputFile;
try {
String masterPwd = mSharedPrefs.getString(MASTER_PWD_STRING, appName);
PdfReader reader = new PdfReader(file, masterPwd.getBytes());
byte[] password;
finalOutputFile = mFileUtils.getUniqueFileName
(file.replace(mContext.getResources().getString(R.string.pdf_ext),
mContext.getString(R.string.decrypted_file)));
password = reader.computeUserPassword();
byte[] input = inputPassword[0].getBytes();
if (Arrays.equals(input, password)) {
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(finalOutputFile));
stamper.close();
reader.close();
return finalOutputFile;
}
} catch (DocumentException | IOException e) {
e.printStackTrace();
}
return null;
}
private boolean removePasswordUsingDefMasterPassword(final String file,
final DataSetChanged dataSetChanged,
final String[] inputPassword) {
String finalOutputFile;
try {
String masterPwd = mSharedPrefs.getString(MASTER_PWD_STRING, appName);
PdfReader reader = new PdfReader(file, masterPwd.getBytes());
byte[] password;
finalOutputFile = mFileUtils.getUniqueFileName
(file.replace(mContext.getResources().getString(R.string.pdf_ext),
mContext.getString(R.string.decrypted_file)));
password = reader.computeUserPassword();
byte[] input = inputPassword[0].getBytes();
if (Arrays.equals(input, password)) {
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(finalOutputFile));
stamper.close();
reader.close();
if (dataSetChanged != null)
dataSetChanged.updateDataset();
new DatabaseHelper(mContext).insertRecord(finalOutputFile, mContext.getString(R.string.decrypted));
final String filepath = finalOutputFile;
StringUtils.getInstance().getSnackbarwithAction(mContext, R.string.snackbar_pdfCreated)
.setAction(R.string.snackbar_viewAction,
v2 -> mFileUtils.openFile(filepath, FileUtils.FileType.e_PDF)).show();
return true;
}
} catch (DocumentException | IOException e) {
e.printStackTrace();
}
return false;
}
private boolean removePasswordUsingInputMasterPassword(final String file,
final DataSetChanged dataSetChanged,
final String[] inputPassword) {
String finalOutputFile;
try {
PdfReader reader = new PdfReader(file, inputPassword[0].getBytes());
finalOutputFile = mFileUtils.getUniqueFileName(
file.replace(mContext.getResources().getString(R.string.pdf_ext),
mContext.getString(R.string.decrypted_file)));
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(finalOutputFile));
stamper.close();
reader.close();
if (dataSetChanged != null)
dataSetChanged.updateDataset();
new DatabaseHelper(mContext).insertRecord(finalOutputFile, mContext.getString(R.string.decrypted));
final String filepath = finalOutputFile;
StringUtils.getInstance().getSnackbarwithAction(mContext, R.string.snackbar_pdfCreated)
.setAction(R.string.snackbar_viewAction, v2 ->
mFileUtils.openFile(filepath, FileUtils.FileType.e_PDF)).show();
return true;
} catch (DocumentException | IOException e) {
e.printStackTrace();
}
return false;
}
}