/*
*
* Panbox - encryption for cloud storage
* Copyright (C) 2014-2015 by Fraunhofer SIT and Sirrix AG
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additonally, third party code may be provided with notices and open source
* licenses from communities and third parties that govern the use of those
* portions, and any licenses granted hereunder do not alter any rights and
* obligations you may have under such open source licenses, however, the
* disclaimer of warranty and limitation of liability provisions of the GPLv3
* will apply to all the product.
*
*/
package org.panbox.mobile.android.gui.fragment;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.UnrecoverableKeyException;
import java.util.ArrayList;
import java.util.Arrays;
import javax.crypto.SecretKey;
import org.panbox.PanboxConstants;
import org.panbox.core.Utils;
import org.panbox.core.crypto.AbstractObfuscatorFactory;
import org.panbox.core.crypto.AndroidObfuscatorFactory;
import org.panbox.core.crypto.CryptCore;
import org.panbox.core.crypto.KeyConstants;
import org.panbox.core.crypto.Obfuscator;
import org.panbox.core.crypto.io.AESGCMRandomAccessFileCompat;
import org.panbox.core.crypto.io.EncRandomAccessInputStream;
import org.panbox.core.crypto.io.EncRandomAccessOutputStream;
import org.panbox.core.exception.FileEncryptionException;
import org.panbox.core.exception.FileIntegrityException;
import org.panbox.core.exception.ObfuscationException;
import org.panbox.core.exception.ShareMetaDataException;
import org.panbox.core.exception.SymmetricKeyDecryptionException;
import org.panbox.core.exception.SymmetricKeyNotFoundException;
import org.panbox.core.identitymgmt.AbstractIdentity;
import org.panbox.core.identitymgmt.IPerson;
import org.panbox.core.identitymgmt.PanboxContact;
import org.panbox.core.keymgmt.AndroidJDBCHelperNonRevokeable;
import org.panbox.core.keymgmt.EncryptedShareKey;
import org.panbox.core.keymgmt.ShareKey;
import org.panbox.core.keymgmt.Volume;
import org.panbox.core.sharemgmt.ShareManagerException;
import org.panbox.mobile.android.R;
import org.panbox.mobile.android.dropbox.vfs.DropboxVirtualFile;
import org.panbox.mobile.android.gui.activity.FileBrowserActivity;
import org.panbox.mobile.android.gui.activity.ShareManagerActivity;
import org.panbox.mobile.android.gui.adapter.FileItemAdapter;
import org.panbox.mobile.android.gui.data.FileItem;
import org.panbox.mobile.android.gui.data.PanboxManager;
import org.panbox.mobile.android.utils.AndroidSettings;
import android.app.Activity;
import android.app.Fragment;
import android.app.ProgressDialog;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.webkit.MimeTypeMap;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
public class FileBrowserFragment extends Fragment implements
FileBrowserActivity.TaskListener, OnItemClickListener {
private final String TAG_CLASS = "FileBrowserFragment:";
private final String TAG_GET_FILE = "GetFile:";
private final String TAG_SYNC_SHARE_CONTENT = "SyncShareContent:";
private final String TAG_UPLOAD_FILE = "UploadFile:";
private final int ERROR_NOT_OWNER = 0x1;
private final int ERROR_COULD_NOT_EXTRACT_KEYS = 0x2;
private final int ERROR_COULD_NOT_FIND_FILE_ON_DISK = 0x3;
private final int ERROR_DECRYPTING = 0x4;
private final int ERROR_DEOBFUSCATING = 0x5;
private int accessStatus = 0;
private ProgressDialog progressDialog;
private boolean isTaskRunning = false;
private boolean isGetFileTaskRunning = false;
private SyncShareContent shareContentTask;
private GetFile getFileTask;
private UploadFile uploadFileTask;
protected Bundle bundle;
private PanboxManager panbox;
private AbstractIdentity identity;
private View fragmentLayout;
private LinearLayout infoBarLine1;
private LinearLayout infoBarLine2;
private LinearLayout infoBarContainer;
private ListView mainLv = null;
private LinearLayout updateButton;
private LinearLayout uploadButton;
private FileItemAdapter adapter = null;
private ArrayList<FileItem> shareContent;
private ArrayList<DropboxVirtualFile> dbList;
private Obfuscator obfuscator;
private SecretKey obfuscationKey;
private ShareKey shareKey;
private String deviceName;
private String shareName;
protected boolean isItemClicked = false;
private OnTouchListener onUpdateAndUploadButtonListener;
private String root;
private String viewPath;
private String path;
private Context context;
private AndroidSettings settings;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
onUpdateAndUploadButtonListener = (OnTouchListener) activity;
}
@Override
public void onCreate(Bundle savedInstanceState) {
Log.v("FileBrowserFragment:", "in onCreate()");
super.onCreate(savedInstanceState);
setRetainInstance(true);
settings = AndroidSettings.getInstance(); // no need to check for exceptions here. It is already done in the parent activity
// we get bundle and generate volume only once and only when fragment is
// created,therefore they are initialized as long as the fragment lives
// if fragment is destroyed as well as the activity while activity was
// stopped, then need to conduct pairing again
bundle = ((FileBrowserActivity) getActivity()).getBundleFromIntent();
if (bundle != null) {
Log.v("FileBrowserFragment:onCreate():",
"shareName is: " + bundle.getString("chosenShare"));
shareName = bundle.getString("chosenShare");
root = File.separator + shareName;
viewPath = bundle.getString("viewPath");
path = bundle.getString("path");
// mDBCon = ((FileBrowserActivity) getActivity()).getmDBCon();
// volume = ((FileBrowserActivity) getActivity()).getVolume();
} else {
// // if bundle is zero, then the FileBrowserActivity was accessed
// in other way than clicking a share item
// // so we need to redirect the user to the ShareManagerActivity
Log.v("FileBrowserFragment:onCreate()",
"undocumented access path => redirect user to the ShareManagerActivity");
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.v("FileBrowserFragment:", "in onCreateView()");
// On orientation change the activity is destroyed and created again,
// however the fragment is not destroyed and during activity creation
// fragment's onCreateView is called
if (!isGetFileTaskRunning) { // if this task is running, than per
// definition the fragment is there as
// well as listview
context = getActivity();
panbox = PanboxManager.getInstance(context);
identity = panbox.getIdentity();
deviceName = settings.getDeviceName();
fragmentLayout = inflater.inflate(R.layout.pb_list_view, container, false);
infoBarContainer = (LinearLayout) fragmentLayout
.findViewById(R.id.pb_infobar_container);
updateButton = (LinearLayout) fragmentLayout.findViewById(R.id.pb_update_container);
uploadButton = (LinearLayout) fragmentLayout.findViewById(R.id.pb_upload_container);
this.uploadButton.setClickable(true);
this.uploadButton.setOnTouchListener(this.onUpdateAndUploadButtonListener);
this.updateButton.setClickable(true);
this.updateButton.setOnTouchListener(this.onUpdateAndUploadButtonListener);
infoBarLine1 = (LinearLayout) inflater.inflate( R.layout.pb_infobar_line, container, false);
infoBarLine2 = (LinearLayout) inflater.inflate( R.layout.pb_infobar_line, container, false);
infoBarContainer.addView(infoBarLine1);
infoBarContainer.addView(infoBarLine2);
mainLv = (ListView) fragmentLayout.findViewById(R.id.pb_listview);
}
mainLv.setOnItemClickListener(this);
return fragmentLayout;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
Log.v("FileBrowserFragment:", "in onActivityCreated()");
super.onActivityCreated(savedInstanceState);
if (bundle != null || (bundle = ((FileBrowserActivity) getActivity()).getBundleFromIntent()) != null) {
setInfoBarView();
// If we are returning here from a screen orientation
// and the AsyncTask is still working, re-create and display the
// progress dialog.
if (isTaskRunning) {
progressDialog = ProgressDialog.show(getActivity(),
getString(R.string.pb_loading),
getString(R.string.pb_please_wait));
} else {
if (shareContent != null) {
populateListView(shareContent);
} else {
shareContentTask = new SyncShareContent(this);
shareContentTask.execute();
}
}
} else {
// if bundle is zero, then the FileBrowserActivity was accessed in
// other way than clicking a share item
// so we need to redirect the user to the ShareManagerActivity
Log.v("FileBrowserFragment:onActivityCreated()",
"undocumented access path => redirect user to the ShareManagerActivity");
}
}
@Override
public void onPreExecute() {
Log.v("FileBrowserFragment:", "in onPreExecute()");
isTaskRunning = true;
progressDialog = ProgressDialog.show(getActivity(),
getString(R.string.pb_loading),
getString(R.string.pb_please_wait));
}
@Override
public void onPostExecute() {
Log.v("FileBrowserFragment:", "in onPostExecute()");
if (progressDialog != null) {
progressDialog.dismiss();
}
isTaskRunning = false;
}
@Override
public void onDetach() {
// All dialogs should be closed before leaving the activity in order to avoid
// the: Activity has leaked window com.android.internal.policy... exception
if (progressDialog != null && progressDialog.isShowing()) {
progressDialog.dismiss();
}
super.onDetach();
}
public void populateListView(ArrayList<FileItem> shareContent) {
Log.v("FileBrowserFragment:populateListView()",
"setting adapter for listview...");
adapter = new FileItemAdapter(getActivity(), R.layout.pb_list_item,
shareContent); // at this step the objects to be mapped to views
// are instantiated, so we can use our adapter
// to convert them to views
mainLv.setAdapter(adapter);
}
public void onItemClick(AdapterView<?> parentAdapter,
android.view.View view, int position, long id) {
String parent = path.substring(0, path.lastIndexOf("/"));
String parentViewPath = File.separator;
if (!viewPath.equals(File.separator)) {
parentViewPath = viewPath.substring(0, viewPath.length() - 1);
parentViewPath = parentViewPath.substring(0,
parentViewPath.lastIndexOf("/") + 1);
}
Log.v("parent: ", parent);
Log.v("parentViewPath: ", parentViewPath);
if (position == 0) {
if (path.equals(root)) {
Toast.makeText(getActivity(),
getString(R.string.pb_already_in_root_text),
Toast.LENGTH_LONG).show();
} else {
path = parent;
viewPath = parentViewPath; // path to the parent directory
setInfoBarView();
shareContentTask = new SyncShareContent(this);
shareContentTask.execute();
}
} else { // position !=0
DropboxVirtualFile file = dbList.get((int) (id - 1)); // id - 1 is needed because the "UptoParent" listview
// entry as the first entry in the listview is added
String decName = shareContent.get((int) id).getName();
String encName = file.getFileName();
if (file.isDirectory()) { // go one level deeper
path = path + File.separator + encName;
viewPath += decName + File.separator;
Log.v("position", String.valueOf(position));
Log.v("path", path);
Log.v("viewPath", viewPath);
setInfoBarView();
shareContentTask = new SyncShareContent(this);
shareContentTask.execute();
} else {
// path points to the obfuscated file in the dropbox (it was
// already deobfuscated here locally => decName),
// now the obfuscated file needs to ne downloaded from the
// dropbox and decrypted
getFileTask = new GetFile(path, encName, decName, this);
getFileTask.execute();
}
}
}
private void setInfoBarView() {
addInfoBarLine(R.id.pb_infobar_container, getString(R.string.pb_share) + ":\t\t\t", shareName, infoBarLine1);
addInfoBarLine(R.id.pb_infobar_container, getString(R.string.pb_path) + ":\t\t\t", viewPath, infoBarLine2);
}
/**
* @param id - id of the infobar container to inflate
* @param name - name of the line
* @param value- value of the line
* @param view - LinearLayout - layout to which name and value textviews are added
*/
public void addInfoBarLine(int id, String name, String value,
LinearLayout infoBarLine) {
TextView nameView = (TextView) infoBarLine
.findViewById(R.id.pb_infobar_line_name);
TextView valueView = (TextView) infoBarLine
.findViewById(R.id.pb_infobar_value);
nameView.setText(name);
valueView.setText(value);
}
public ArrayList<FileItem> getShareContent() {
return shareContent;
}
public void setShareContent(ArrayList<FileItem> shareContent) {
this.shareContent = shareContent;
}
public String getShareName() {
return shareName;
}
public void setShareName(String shareName) {
this.shareName = shareName;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public String getViewPath() {
return viewPath;
}
public void setViewPath(String viewPath) {
this.viewPath = viewPath;
}
@Override
public void onStart() {
Log.v("FileBrowserFragment:", "in onStart()");
super.onStart();
if (bundle == null
&& (bundle = ((FileBrowserActivity) getActivity())
.getBundleFromIntent()) == null) { // need to retrieve bundle also here, because it is the only
// method that is called when activity's onNewIntent() is called
Intent shareManager = new Intent(getActivity(),
ShareManagerActivity.class);
startActivity(shareManager);
}
}
@Override
public void onPause() {
Log.v("FileBrowserFragment:", "in onPause()");
super.onPause();
}
@Override
public void onStop() {
Log.v("FileBrowserFragment:", "in onStop()");
super.onStop();
}
@Override
public void onDestroy() {
Log.v("FileBrowserFragment:", "in onDestroy()");
super.onDestroy();
}
@Override
public void onResume() {
super.onResume();
}
private class GetFile extends AsyncTask<Void, Void, Boolean> {
private String path;
private String encName;
private String decName;
private FileBrowserActivity.TaskListener listener;
private GetFile(String path, String encName, String decName,
FileBrowserActivity.TaskListener listener) {
this.path = path;
this.encName = encName;
this.decName = decName;
this.listener = listener;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
Log.v(TAG_CLASS + TAG_GET_FILE, " in onPreExecute()");
listener.onPreExecute();
isGetFileTaskRunning = true;
}
@Override
public void onPostExecute(Boolean result) {
super.onPostExecute(result);
Log.v(TAG_CLASS + TAG_GET_FILE, " in onPostExecute()");
listener.onPostExecute();
isGetFileTaskRunning = false;
if (accessStatus == ERROR_COULD_NOT_FIND_FILE_ON_DISK)
Toast.makeText(context,
getString(R.string.pb_could_not_find_file_on_disk),
Toast.LENGTH_LONG).show();
if (accessStatus == ERROR_DECRYPTING)
Toast.makeText(context,
getString(R.string.pb_could_not_decrypt),
Toast.LENGTH_LONG).show();
}
@Override
protected Boolean doInBackground(Void... arg0) {
Log.v(TAG_CLASS + TAG_GET_FILE, "in doInBackground()");
String baseDir;
String state = Environment.getExternalStorageState();
baseDir = settings.getConfDir();
Log.v("Configuration Dir: ", baseDir);
if (!state.equals(Environment.MEDIA_MOUNTED)) {
Log.v(TAG_CLASS + TAG_GET_FILE, "No external storage available, store files in the internal memory");
baseDir = settings.getConfDir();
} else
baseDir = Environment.getExternalStorageDirectory().getPath();
File encryptedFile = new File(baseDir + path + File.separator + encName);
encryptedFile.getParentFile().mkdirs();
if (encryptedFile.exists()) {
encryptedFile.delete();
}
try {
encryptedFile.createNewFile();
} catch (IOException e) {
Log.v(TAG_CLASS + TAG_GET_FILE,
"Error while creating a new file ");
e.printStackTrace();
}
Log.v(TAG_CLASS + TAG_GET_FILE, "File successfully created:");
panbox.getMyDBCon().downloadFile(path + File.separator + encName, encryptedFile.getPath());
Log.v(TAG_CLASS + TAG_GET_FILE, "File downloaded:");
try {
AESGCMRandomAccessFileCompat rafc = AESGCMRandomAccessFileCompat
.getInstance(encryptedFile, true); // rafc is then an
// instance of
// EncRandomAccessFile
rafc.open();
if ((shareKey = panbox.getCachedShareKey()) == null)
throw new FileEncryptionException(
"The share key is not set");
rafc.initWithShareKey(shareKey.key);
EncRandomAccessInputStream encryptedInputStream = new EncRandomAccessInputStream(
rafc); // creates an inputsream of encrypted file
File realDecrypted = new File(baseDir + path + File.separator
+ decName);
realDecrypted.getParentFile().mkdirs();
if (realDecrypted.exists()) {
realDecrypted.delete();
}
try {
realDecrypted.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(realDecrypted));
byte[] decBytes = new byte[1024];
while (encryptedInputStream.read(decBytes) != -1) {
bos.write(decBytes);
bos.flush();
}
bos.close();
encryptedInputStream.close();
Intent i = new Intent();
i.setAction(Intent.ACTION_VIEW);
String extension = MimeTypeMap.getFileExtensionFromUrl(Uri
.fromFile(realDecrypted).toString());
String mimetype = MimeTypeMap.getSingleton()
.getMimeTypeFromExtension(extension);
try {
i.setDataAndType(Uri.fromFile(realDecrypted), mimetype);
startActivity(i);
} catch (NullPointerException e) {
accessStatus = ERROR_COULD_NOT_FIND_FILE_ON_DISK;
e.printStackTrace();
} catch (ActivityNotFoundException e) {
i.setDataAndType(Uri.fromFile(realDecrypted), "text/*");
startActivity(i);
e.printStackTrace();
}
} catch (FileIntegrityException e) {
Log.v(TAG_CLASS + TAG_GET_FILE, e.getMessage());
accessStatus = ERROR_DECRYPTING;
e.printStackTrace();
} catch (FileEncryptionException e) {
Log.v(TAG_CLASS + TAG_GET_FILE, e.getMessage());
accessStatus = ERROR_DECRYPTING;
e.printStackTrace();
} catch (IOException e) {
Log.v(TAG_CLASS + TAG_GET_FILE, e.getMessage());
accessStatus = ERROR_DECRYPTING;
e.printStackTrace();
}
return false;
}
}
private class UploadFile extends AsyncTask<Void, Void, Boolean> {
String fileToUpload;
FileBrowserActivity.TaskListener listener;
public UploadFile(String fileToUpload, FileBrowserActivity.TaskListener listener){
this.fileToUpload = fileToUpload;
this.listener = listener;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
Log.v(TAG_CLASS + TAG_UPLOAD_FILE, " in onPreExecute()");
listener.onPreExecute();
}
@Override
public void onPostExecute(Boolean result) {
super.onPostExecute(result);
Log.v(TAG_CLASS + TAG_UPLOAD_FILE, " in onPostExecute()");
listener.onPostExecute();
}
@Override
protected Boolean doInBackground(Void... params) {
Log.v(TAG_CLASS + TAG_UPLOAD_FILE, "uploading file: " + fileToUpload + " to desitnation: " + path);
String realFileName = fileToUpload.substring(fileToUpload.lastIndexOf("/") + 1, fileToUpload.length());
String obfuscatedFileName = null;
String ivPath;
String iv;
AbstractObfuscatorFactory aof = null;
try {
aof = AbstractObfuscatorFactory
.getFactory(AndroidObfuscatorFactory.class);
} catch (ClassNotFoundException e) {
Log.v(TAG_CLASS + TAG_GET_FILE, e.getMessage());
accessStatus = ERROR_DEOBFUSCATING;
e.printStackTrace();
} catch (InstantiationException e) {
Log.v(TAG_CLASS + TAG_GET_FILE, e.getMessage());
accessStatus = ERROR_DEOBFUSCATING;
e.printStackTrace();
} catch (IllegalAccessException e) {
Log.v(TAG_CLASS + TAG_GET_FILE, e.getMessage());
accessStatus = ERROR_DEOBFUSCATING;
e.printStackTrace();
} catch (Exception e) {
Log.v(TAG_CLASS + TAG_GET_FILE, e.getMessage());
accessStatus = ERROR_DEOBFUSCATING;
e.printStackTrace();
}
try {
obfuscator = ((AndroidObfuscatorFactory) aof).getInstance(
path, shareName, panbox.getMyDBCon(), context);
String[] obfNameAndIV = obfuscator.obfuscate(realFileName, panbox.getCachedObfuscationKey());
obfuscatedFileName = obfNameAndIV[0];
ivPath = obfNameAndIV[1];
iv = ivPath.substring(ivPath.lastIndexOf("/") + 1, ivPath.length());
File ivDir = context.getDir("iv_dir", Context.MODE_PRIVATE); //Creating an internal dir;
File ivFile = new File(ivDir, iv); //Getting a file within the dir.
//TODO: emptying the file with help of next two lines is a workaround that is necessary to prevent file not empty exception thrown by AESGCMRandomAccessFileCompat.
// Must be removed as soon as open() of AESGCMRandomAccessFileCompat is used
FileOutputStream out = new FileOutputStream(ivFile); //Use the stream as usual to write into the file.
out.close();
Log.v(TAG_CLASS + TAG_UPLOAD_FILE, "obfuscated filename: " + obfuscatedFileName);
Log.v(TAG_CLASS + TAG_UPLOAD_FILE, "ivPath: " + ivPath);
String locOfIV = ivFile.getAbsolutePath();
panbox.getMyDBCon().uploadFile(locOfIV, ivPath);
} catch (ObfuscationException e) {
Log.e(TAG_CLASS + TAG_UPLOAD_FILE,
"Failed to get AndroidObfuscatorFactory.", e);
} catch (FileNotFoundException e) {
Log.e(TAG_CLASS + TAG_UPLOAD_FILE,
"Failed to get create new file.", e);
} catch (IOException e) {
Log.e(TAG_CLASS + TAG_UPLOAD_FILE,
"Failed to create iv.", e);
}
File fileToEncrypt = new File(fileToUpload);
File encDir = context.getDir("enc_dir", Context.MODE_PRIVATE);
File fileEncrypted = new File(encDir, obfuscatedFileName);
//TODO: emptying the file with help of next try block is a workaround that is necessary to prevent file not empty exception thrown by AESGCMRandomAccessFileCompat.
// Must be removed as soon as open() of AESGCMRandomAccessFileCompat is used
try {
FileOutputStream out = new FileOutputStream(fileEncrypted); //Use the stream as usual to write into the file.
out.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
BufferedInputStream bis = null;
EncRandomAccessOutputStream outStream = null;
try {
outStream = new EncRandomAccessOutputStream(
AESGCMRandomAccessFileCompat.create(0, shareKey.key, fileEncrypted));
bis = new BufferedInputStream(new FileInputStream(fileToEncrypt));
byte[] buf = new byte[1000];
while( bis.read(buf) != -1){
outStream.write(buf);
}
outStream.flush();
panbox.getMyDBCon().uploadFile(fileEncrypted.getAbsolutePath(), path + File.separator + obfuscatedFileName);
} catch (FileEncryptionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
if (outStream != null)
outStream.close();
if (bis != null)
bis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return true;
}
}
public void uploadFile(String fileToUpload){
uploadFileTask = new UploadFile(fileToUpload,this);
uploadFileTask.execute();
}
private class SyncShareContent extends AsyncTask<Void, Void, Boolean> {
private FileBrowserActivity.TaskListener listener;
public SyncShareContent(FileBrowserActivity.TaskListener listener) {
this.listener = listener;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
Log.v(TAG_CLASS + TAG_SYNC_SHARE_CONTENT, " in onPreExecute()");
listener.onPreExecute();
}
@Override
protected Boolean doInBackground(Void... arg0) {
Log.v(TAG_CLASS + TAG_SYNC_SHARE_CONTENT, "in doInBackground()");
System.err.println("Before filelist");
long timeBefore = System.currentTimeMillis();
ArrayList<DropboxVirtualFile> fileNameList = panbox.getMyDBCon()
.listFiles(path, panbox.getVolume());
AbstractObfuscatorFactory aof = null;
try {
aof = AbstractObfuscatorFactory
.getFactory(AndroidObfuscatorFactory.class);
} catch (ClassNotFoundException e) {
Log.v(TAG_CLASS + TAG_GET_FILE, e.getMessage());
accessStatus = ERROR_DEOBFUSCATING;
e.printStackTrace();
} catch (InstantiationException e) {
Log.v(TAG_CLASS + TAG_GET_FILE, e.getMessage());
accessStatus = ERROR_DEOBFUSCATING;
e.printStackTrace();
} catch (IllegalAccessException e) {
Log.v(TAG_CLASS + TAG_GET_FILE, e.getMessage());
accessStatus = ERROR_DEOBFUSCATING;
e.printStackTrace();
} catch (Exception e) {
Log.v(TAG_CLASS + TAG_GET_FILE, e.getMessage());
accessStatus = ERROR_DEOBFUSCATING;
e.printStackTrace();
}
Log.v(TAG_CLASS + TAG_SYNC_SHARE_CONTENT, "path: " + path);
Log.v(TAG_CLASS + TAG_SYNC_SHARE_CONTENT, "shareName: " + shareName);
if (path.equals(File.separator + shareName)) { // if we are not in root directory any more, then if
// share folder was clicked, in this case parent
// points to root dir
IPerson owner = checkOwnership();
if (owner != null) { // OK, user is an owner of the share, start
// extracting obfuscation and share keys
Log.v("FileBrowserFragment:SyncShareContent:doInBackground()",
"user is the owner of the share");
extractKeys(owner);
// extractKeys(); // a mockup function. use if only keys are
// needed without extracting them from the pbmeta.db
} else { // this user is not an owner of the share
// TODO if this identity is not the owner of the share, then
// this identity should be in possession of necessary
// parameters to initialize the VolumeParams object
// which in turn is used to instantiate the sharemetadata
// object
// accessStatus = ERROR_NOT_OWNER;
Log.v(TAG_CLASS + TAG_SYNC_SHARE_CONTENT
+ "doInBackground()",
"user is not the owner of the share");
accessStatus = ERROR_NOT_OWNER;
return false;
}
deobfuscateFiles(fileNameList, aof);
} else { // we have clicked a folder in the share
deobfuscateFiles(fileNameList, aof);
long timeAfter = System.currentTimeMillis();
System.err.println("Files in dir: " + fileNameList.size() + " time needed for deobfuscation: " + (timeAfter - timeBefore));
}
return true;
}
private IPerson checkOwnership() {
Log.v(TAG_CLASS + TAG_SYNC_SHARE_CONTENT, "in checkOnwership()");
IPerson owner = null;
try {
byte[] ownerFp; // digest of this identity
String metaDataDir = path + File.separator
+ PanboxConstants.PANBOX_SHARE_METADATA_DIRECTORY
+ File.separator;
MessageDigest md;
try {
md = MessageDigest.getInstance(
// throws no such algo exception
KeyConstants.PUBKEY_FINGERPRINT_DIGEST,
KeyConstants.PROV_BC);
} catch (NoSuchProviderException e1) {
// TODO Auto-generated catch block
throw new ShareManagerException(
"Error initializing message-digest!", e1);
}
ownerFp = new byte[md.getDigestLength()]; // this will hold the
// owner's digest
// read from the
// owner.pbox file
BufferedInputStream bis = new BufferedInputStream(
panbox.getMyDBCon()
.downloadFileStream(
metaDataDir
+ PanboxConstants.PANBOX_SHARE_OWNER_FILE));
bis.read(ownerFp);
bis.close();
byte[] c = null;
if (identity.getCertSign() != null)
c = md.digest(identity.getCertSign().getPublicKey()
.getEncoded());
if (Arrays.equals(ownerFp, c)) {
owner = identity;
} else {
for (PanboxContact contact : identity.getAddressbook()
.getContacts()) {
if (contact.getCertSign() != null)
c = md.digest(contact.getCertSign().getPublicKey()
.getEncoded());
md.reset();
if (Arrays.equals(ownerFp, c)) {
owner = contact;
break;
}
}
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ShareManagerException e) {
// TODO Auto-generated catch block
throw new RuntimeException(e);
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
throw new RuntimeException(e);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return owner;
}
private void extractKeys(IPerson owner) {
Log.v(TAG_CLASS + TAG_SYNC_SHARE_CONTENT, "in extractKeys()");
try {
PublicKey publicKeyForDevice = identity
.getPublicKeyForDevice(deviceName);
PrivateKey privateKeyForDevice = identity
.getPrivateKeyForDevice(
KeyConstants.OPEN_KEYSTORE_PASSWORD, deviceName);
String destination = settings.getConfDir() + File.separator
+ Volume.SPL_FILE;
String source = path + File.separator + ".panbox"
+ File.separator + Volume.SPL_FILE;
MessageDigest md = null;
String fingerprint = null;
try {
md = MessageDigest.getInstance("SHA-256");
fingerprint = Utils.bytesToHex(md.digest(identity
.getPublicKeySign().getEncoded()));
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
throw new RuntimeException(e);
}
String destinationDL = settings.getConfDir() + File.separator
+ fingerprint + ".db";
String sourceDL = path + File.separator + ".panbox"
+ File.separator + fingerprint + ".db";
Log.v(Volume.SPL_FILE + " download destination:", destination);
boolean success = false;
if (panbox.getMyDBCon().downloadFile(source, destination)) {
Log.v(Volume.SPL_FILE,
"downloaded, size: "
+ String.valueOf((new File(destination))
.getTotalSpace()));
if (panbox.getMyDBCon().downloadFile(sourceDL,
destinationDL)) {
Log.v(fingerprint,
"downloaded, size: "
+ String.valueOf((new File(
destinationDL)).getTotalSpace()));
success = true;
} else {
Log.v(fingerprint, "fail to download");
}
} else {
Log.v(Volume.SPL_FILE, "fail to download");
}
if (!success) {
accessStatus = ERROR_COULD_NOT_EXTRACT_KEYS;
return;
}
Volume vol = new Volume(
new AndroidJDBCHelperNonRevokeable(destination,
destinationDL, identity.getPublicKeySign()));
vol.loadShareMetaData((owner != null ? owner.getCertSign()
.getPublicKey() : null));
obfuscationKey = CryptCore.decryptSymmertricKey(
vol.getEncryptedObfuscationKey(publicKeyForDevice),
privateKeyForDevice);
panbox.setCachedObfuscationKey(obfuscationKey);
EncryptedShareKey encryptedShareKey = vol
.getLatestEncryptedShareKey(publicKeyForDevice);
SecretKey secretKey = CryptCore.decryptSymmertricKey(
encryptedShareKey.encryptedKey, privateKeyForDevice);
shareKey = new ShareKey(secretKey, encryptedShareKey.version);
panbox.setCachedShareKey(shareKey);
} catch (UnrecoverableKeyException e) {
Log.v(TAG_CLASS + TAG_SYNC_SHARE_CONTENT, e.getMessage());
accessStatus = ERROR_COULD_NOT_EXTRACT_KEYS;
e.printStackTrace();
} catch (SymmetricKeyDecryptionException e) {
Log.v(TAG_CLASS + TAG_SYNC_SHARE_CONTENT, e.getMessage());
accessStatus = ERROR_COULD_NOT_EXTRACT_KEYS;
e.printStackTrace();
} catch (SymmetricKeyNotFoundException e) {
Log.v(TAG_CLASS + TAG_SYNC_SHARE_CONTENT, e.getMessage());
accessStatus = ERROR_COULD_NOT_EXTRACT_KEYS;
e.printStackTrace();
} catch (ShareMetaDataException e) {
Log.v(TAG_CLASS + TAG_SYNC_SHARE_CONTENT, e.getMessage());
accessStatus = ERROR_COULD_NOT_EXTRACT_KEYS;
e.printStackTrace();
}
}
/**
* This method is used to deobfuscate filenames using the previously
* obtained obfuscationKey
*
* @param fileNameList
* @param aof
*/
private void deobfuscateFiles(
ArrayList<DropboxVirtualFile> fileNameList,
AbstractObfuscatorFactory aof) {
Log.v(TAG_CLASS + TAG_SYNC_SHARE_CONTENT, "in deobfuscateFiles()");
String deobfuscated;
String modified;
if (accessStatus != ERROR_COULD_NOT_EXTRACT_KEYS && accessStatus != ERROR_NOT_OWNER) {
try {
dbList = new ArrayList<DropboxVirtualFile>();
obfuscator = ((AndroidObfuscatorFactory) aof).getInstance(
path, shareName, panbox.getMyDBCon(), context);
shareContent = new ArrayList<FileItem>();
} catch (ObfuscationException e) {
Log.e("FileBrowserFragment",
"Failed to get AndroidObfuscatorFactory.");
return;
}
for (DropboxVirtualFile dbf : fileNameList) {
try {
if (!dbf.getFileName().endsWith("~")
&& !dbf.getFileName().equals(".panbox")
&& !dbf.getFileName().equals(".directory")
&& !dbf.getFileName().equals(".dropbox")) {
deobfuscated = obfuscator.deObfuscate(
dbf.getFileName(), obfuscationKey);
modified = panbox.getMyDBCon().getFileInfo(
dbf.getPath()).modified;
shareContent.add(new FileItem(deobfuscated, dbf
.getPath(), modified.substring(0,
modified.lastIndexOf("+")),
panbox.getMyDBCon().getFileInfo(
dbf.getPath()).size, dbf
.isDirectory() ? String
.valueOf((new DropboxVirtualFile(
dbf.getPath(), panbox
.getVolume()))
.list().length) : "", dbf
.isDirectory()));
dbList.add(dbf);
}
} catch (ObfuscationException e) {
Log.v("FileBrowserFragment", "Could not deobfuscate file. Will ignore this one: " + dbf.getFileName());
}
}
if (path.equals(root)) {
shareContent.add(0, new FileItem("/", path, "", "", "0", true)); // no way up, because already in the root
}
else {
shareContent.add(0, new FileItem("..", path, "", "", "0", true)); // still can go at least one level up
}
}
}
@Override
public void onPostExecute(Boolean result) {
super.onPostExecute(result);
Log.v(TAG_CLASS + TAG_SYNC_SHARE_CONTENT, " in onPostExecute()");
panbox = PanboxManager.getInstance(context); // TODO:Here need to make sure that the context is available
if (accessStatus == ERROR_NOT_OWNER) {
Toast.makeText(context,
getString(R.string.pb_not_share_onwer_text),
Toast.LENGTH_LONG).show();
Intent sharesActivity = new Intent(context,
ShareManagerActivity.class);
startActivity(sharesActivity);
} else if (accessStatus == ERROR_COULD_NOT_EXTRACT_KEYS) {
Toast.makeText(context,
getString(R.string.pb_obtain_credentials),
Toast.LENGTH_LONG).show();
Intent sharesActivity = new Intent(context,
ShareManagerActivity.class);
startActivity(sharesActivity);
} else if (accessStatus == ERROR_DEOBFUSCATING) {
Toast.makeText(context,
getString(R.string.pb_could_not_deobfuscate),
Toast.LENGTH_LONG).show();
// Intent sharesActivity = new Intent(context,
// ShareManagerActivity.class);
// startActivity(sharesActivity);
} else if (shareContent != null)
populateListView(shareContent);
listener.onPostExecute();
}
}
}