package ve.gob.cenditel.tibisaymovil; import java.io.File; import java.io.FileOutputStream; import java.security.cert.X509Certificate; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import ee.sk.digidoc.DataFile; import ee.sk.digidoc.SignedDoc; import ee.sk.utils.ConfigManager; import ee.sk.xmlenc.EncryptedData; import ee.sk.xmlenc.EncryptedKey; import ve.gob.cenditel.tibisaymovil.R; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.View.OnClickListener; import android.view.Window; import android.webkit.MimeTypeMap; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.RadioButton; import android.widget.TextView; import android.widget.AdapterView.OnItemClickListener; import android.widget.Toast; public class SelectCertificateToEncryptActivity extends Activity implements OnItemClickListener, OnClickListener { private File cwd; private File selected; private FileBrowserView viewHolder; private FileListAdapter listAdapter; private String filterMImeType = "application/x-pem-file"; // cadena que mantiene la ruta del archivo a compartir private String fileToEncrypt = null; // cadena que mantiene la ruta del certificado del destinatario private String certificateToEncrypt = null; // cadena que mantiene la ruta del directorio de certificados String certificateDirFiles = null; // cadena que mantiene la ruta del directorio archivos cifrados String encrypted_dir_files = null; @Override protected void onCreate(Bundle savedInstanceState) { //Estilando la barra de titulo final boolean customTitleSupported = requestWindowFeature(Window.FEATURE_CUSTOM_TITLE); super.onCreate(savedInstanceState); this.viewHolder = new FileBrowserView(); // obtener la ruta del archivo que se va a cifrar Bundle bundle = getIntent().getExtras(); fileToEncrypt = bundle.getString("fileToEncrypt"); if (savedInstanceState != null) { if(savedInstanceState.getString("selected") != null) this.selected = new File(savedInstanceState.getString("selected")); if (this.selected != null) { SelectCertificateToEncryptActivity.this.updateButton (SelectCertificateToEncryptActivity.this.viewHolder.accept,true); } this.cwd = new File(savedInstanceState.getString("cwd")); this.viewHolder.fileList.setAdapter(this.listAdapter = new FileListAdapter(this.cwd.getAbsolutePath(), filterMImeType)); } else { this.selected = null; //this.viewHolder.fileList.setAdapter(this.listAdapter = new FileListAdapter()); certificateDirFiles = Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + getResources().getString(R.string.app_name) + "/" + getResources().getString(R.string.certificates_dir) + "/"; this.viewHolder.fileList.setAdapter(this.listAdapter = new FileListAdapter(certificateDirFiles, filterMImeType)); encrypted_dir_files = Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + getResources().getString(R.string.app_name) + "/" + getResources().getString(R.string.encrypted_dir_files) + "/"; } boolean enabled = false; if (this.selected != null) enabled = this.viewHolder.accept.isEnabled(); SelectCertificateToEncryptActivity.this.updateButton (SelectCertificateToEncryptActivity.this.viewHolder.accept,enabled); //Estilando Barra de titulo if(customTitleSupported) getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.title_bar); } /** * Provides the data to be shown in the file browser ListView. * * @author José M. Prieto (jmprieto@emergya.com) */ private class FileListAdapter extends BaseAdapter { private final ArrayList directories; private final ArrayList files; private FileListAdapter() { this("/",filterMImeType); } private FileListAdapter(String location) { this(location, ""); } private FileListAdapter(String location, String filterMimeType) { Log.d("***location", location); Log.d("***filterMimeType", filterMimeType); directories = new ArrayList(); files = new ArrayList(); //Obtiene etiqueta que se colocará antes del path que visualizará el usuario String toPathText = SelectCertificateToEncryptActivity.this.getString(R.string.pathstring)+": "; //Coloca el texto de la etiqueta en la vista SelectCertificateToEncryptActivity.this.viewHolder.pathString.setText(toPathText); //Coloca el texto con el path actual SelectCertificateToEncryptActivity.this.viewHolder.path.setText(location); //Crea un objeto file cwd con la ubicacion dada en location SelectCertificateToEncryptActivity.this.cwd = new File(location); //Obtiene el directorio padre del objeto file cwd File parent = SelectCertificateToEncryptActivity.this.cwd.getParentFile(); //Si tiene un padre, lo agrega en la posición cero de la lista de directorios if (parent != null) { directories.add(0, parent); Log.d("***", "directories.add(0, parent)"); Log.d("***", parent.getAbsolutePath()); } Log.d("***cwd", SelectCertificateToEncryptActivity.this.cwd.getAbsolutePath()); //Crea un arreglo con las lista de archivos contenidos en el directorio cwd File[] ls = SelectCertificateToEncryptActivity.this.cwd.listFiles(); if (ls != null) { Log.d("***", "ls != null"); for (File f : ls) { //recorre todos los archivos contenidos en el directorio if (FsUtils.isHiddenOrNotReadable(f)) { // Si son ocultos no hace nada Log.d("***", "archivo oculto o no legible"); continue; } // Si son directorios los agrega a la lista de directorios a partir de la posición 1 // En la posición 0 se encuentra el directorio padre if (f.isDirectory()) { directories.add(f); Log.d("***", "directories.add(f)"); } else // De lo contrario lo agrega a la lista de archivos { Log.d("***", "agregar archivo a la lista"); //Valida tipo de archivo a mostrar Uri selectedUri = Uri.fromFile(f); String fileExtension = MimeTypeMap.getFileExtensionFromUrl(selectedUri.toString()); String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExtension); //Toast.makeText(SelectCertificateToEncryptActivity.this, //"FileExtension: " + fileExtension + "\n" + //"MimeType: " + mimeType, //Toast.LENGTH_LONG).show(); //Filtra por mimeType: se consideran los .pem .crt .cer //if(filterMimeType.isEmpty() || /*filterMimeType == mimeType*/ fileExtension.equals("pem") if(fileExtension.equals("pem") || fileExtension.equals("crt") || fileExtension.equals("cer")) files.add(f); } } }else{ Log.d("***", "ls == null"); } Collections.sort(directories); // Ordena los directorios alfabeticamente Collections.sort(files); // Ordena los archivos alfabeticamente } /** * Retorna cantidad total de elementos que se listarán en el directorio. */ @Override public int getCount() { return directories.size() + files.size(); } /** * Dada una posición en el listado del directorio, retorna un archivo o directorio * según corresponda. */ @Override public File getItem(int position) { if (position < directories.size()) { return directories.get(position); } else { return files.get(position - directories.size()); } } /** * Retorna un código hash para el archivo, permite comparar si dos archivos son los mismos */ @Override public long getItemId(int position) { return getItem(position).hashCode(); } /** * Crea la visualización de cada item del fileBrowser */ @Override public View getView(int position, View convertView, ViewGroup parent) { //Crea la vista de cada fila del filebrowser a partir del layout if (convertView == null) { LayoutInflater inflater = LayoutInflater.from(SelectCertificateToEncryptActivity.this); convertView = inflater.inflate(R.layout.file_to_verify_bdoc_signature_item, parent, false); } // Se enlaza a cada componente del layout ImageView image = (ImageView) convertView.findViewById(R.id.type_image); TextView fileName = (TextView) convertView.findViewById(R.id.filename_text); TextView modified = (TextView) convertView.findViewById(R.id.filename_modified); // Se obtiene el archivo ubicado en position File file = getItem(position); //RadioButton RadioButton radio = (RadioButton) convertView.findViewById(R.id.file_radio); radio.setFocusable(false); // Se asignan los iconos según el tipo de archivo y se oculta el radio en los directorios if (file.isDirectory()) { image.setImageResource(R.drawable.ic_carpeta); radio.setVisibility(View.INVISIBLE); radio.setChecked(false); } else { image.setImageResource(R.drawable.ic_archivo); radio.setVisibility(View.VISIBLE); if (SelectCertificateToEncryptActivity.this.selected == null || SelectCertificateToEncryptActivity.this.selected.hashCode() != file.hashCode()){ radio.setChecked(false); } else{ radio.setChecked(true); } } // Si es el directorio que hace referencia al padre le coloca como nombre ".." if (file.isDirectory() && position == 0 && ! "/".equals(SelectCertificateToEncryptActivity.this.cwd.getAbsolutePath())) { fileName.setText(".."); } else { fileName.setText(file.getName()); } //Datos de modificación del archivo SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy"); Date date = new Date(file.lastModified()); String dateString = SelectCertificateToEncryptActivity.this.getString(R.string.modified)+": "; if (file.lastModified()>0) modified.setText(dateString+sdf.format(date)); else modified.setText(dateString+"-"); return convertView; } /** * Controla la selección de cada item del fileBrowser */ public void select(ListView parent, int position) { File item = getItem(position); //Si es un directorio el seleccionado se hace un llamado del fileBrowser del directorio if (item.isDirectory()) { parent.setAdapter(SelectCertificateToEncryptActivity.this.listAdapter = new FileListAdapter(item.getAbsolutePath(), filterMImeType)); } else { // Si es un archivo //Se agrega el archivo a la lista de seleccionados si no se encuentra en la misma if (SelectCertificateToEncryptActivity.this.selected == null || SelectCertificateToEncryptActivity.this.selected.hashCode() != item.hashCode()){ SelectCertificateToEncryptActivity.this.selected = item; SelectCertificateToEncryptActivity.this.updateButton(SelectCertificateToEncryptActivity.this.viewHolder.accept,true); } else{ // De lo contrario se elimina de la lista de seleccionados SelectCertificateToEncryptActivity.this.selected = null; SelectCertificateToEncryptActivity.this.updateButton(SelectCertificateToEncryptActivity.this.viewHolder.accept,false); } notifyDataSetChanged(); } } } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putParcelable("intent", this.getIntent()); outState.putString("cwd", this.cwd.getAbsolutePath()); if(this.selected != null) outState.putString("selected", this.selected.getAbsolutePath()); } private void updateButton(View v, boolean bool) { try{ v.setEnabled(bool); if (v instanceof TextView){ Drawable icon = ((TextView)v).getCompoundDrawables()[1]; if (icon!=null) if (bool) icon.setAlpha(255); else icon.setAlpha(127); } if (v instanceof ImageView){ ImageView result = (ImageView) v; if (bool) result.setAlpha(255); else result.setAlpha(127); } }catch(NullPointerException e){} } private void updateButton(LinearLayout layout, boolean bool) { try{ layout.setEnabled(bool); for (int i=0; i parent, View view, int position, long id) { if (parent.getId() == R.id.file_list) { // user selects a file this.listAdapter.select((ListView) parent, position); } else { // user de-selects a file //this.listAdapter.addIfSameDirectory(selectedAdapter.doUnselect((ListView) parent, position)); } //this.viewHolder.numSelected.setText(Integer.toString(this.selected.size())); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.button_clear_zone: this.selected = null; this.listAdapter.notifyDataSetChanged(); //this.viewHolder.numSelected.setText(""+this.selected.size()); this.updateButton(this.viewHolder.accept, false); break; case R.id.button_accept_zone: // lanzar intent para compartir el archivo seleccionado //fileToEncrypt = SelectCertificateToEncryptActivity.this.selected.getAbsolutePath(); certificateToEncrypt = SelectCertificateToEncryptActivity.this.selected.getAbsolutePath(); Toast.makeText(getApplicationContext(), "SelectCertificateToEncryptActivity: "+certificateToEncrypt, Toast.LENGTH_SHORT).show(); encryptFile(fileToEncrypt, certificateToEncrypt); break; } } // funcion para compartir el archivo private void shareIt() { Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND); File file = new File(fileToEncrypt); Uri uri = Uri.fromFile(file); Log.i("DEBUG", file.getPath()); //Log.d("******", getMimeType(file.getPath())); //shareIntent.setDataAndType(uri, getMimeType(file.getPath())); shareIntent.putExtra(Intent.EXTRA_STREAM, uri); shareIntent.setType("application/*"); startActivity(Intent.createChooser(shareIntent, getResources().getText(R.string.share_it_using))); } /** * Cifra el archivo pasado como argumento * * @return void */ // funcion para desplegar el gestor de certificados de destinatarios para cifrar private void encryptFile(String fileToEncrypt, String certificateToEncrypt) { Toast.makeText(getApplicationContext(), "Encrypting file: " + fileToEncrypt, Toast.LENGTH_SHORT).show(); // TODO chequear que se pueda escribir en el directorio /mnt/sdcard/TibisayMovil/EncryptedFiles // chequear disponibilidad de directorio de certificados if (!checkCertificatesDirectoryAvailability()){ Toast.makeText(getApplicationContext(), "SelectCertificateToEncryptActivity: directorio no disponible", Toast.LENGTH_SHORT).show(); finish(); return; } ConfigManager.init("jar://jdigidoc.cfg"); Log.d("despues de:", "ConfigManager.init"); /** signed doc object if used */ SignedDoc m_sdoc; m_sdoc = null; /** encrypted data object if used */ EncryptedData m_cdoc; m_cdoc = null; String inFile = null, outFile = null; String certFile = null; String recipient = null; String keyName = null; String carriedKeyName = null; String sId = null; inFile = fileToEncrypt; certFile = certificateToEncrypt; // agregar el destinatario try { if (m_cdoc == null){ Log.d("m_cdoc == null", "-"); m_cdoc = new EncryptedData(null, null, null, EncryptedData.DENC_XMLNS_XMLENC, EncryptedData.DENC_ENC_METHOD_AES128); } Log.d("Adding recipient", certFile); X509Certificate recvCert = SignedDoc.readCertificate(new File(certFile)); if (recvCert != null && recipient == null) recipient = SignedDoc.getCommonName(recvCert.getSubjectDN().getName()); Log.d("Recipient", recipient); if (sId == null){ int n = m_cdoc.getNumKeys() + 1; sId = "ID" + n; } EncryptedKey ekey = new EncryptedKey(sId, recipient, EncryptedData.DENC_ENC_METHOD_RSA1_5, keyName, carriedKeyName, recvCert); m_cdoc.addEncryptedKey(ekey); }catch(Exception e){ Log.d("Error adding EncryptedKey: ", e.getMessage()); Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show(); showDialog(getResources().getString(R.string.msg_encryption_error), e.getMessage()); return; } // ejecutar el cifrado try { Log.d("Encrypting file:", inFile + " to: " + outFile); File fIn = new File(inFile); // create a ddoc intermediate file m_sdoc = new SignedDoc(SignedDoc.FORMAT_DIGIDOC_XML, SignedDoc.VERSION_1_3); Log.d("Encrypting file:", "paso new SignedDoc"); DataFile df = m_sdoc.addDataFile(new File(inFile), SignedDoc.xmlns_digidoc13, DataFile.CONTENT_EMBEDDED_BASE64); Log.d("Encrypting file:", "paso addDataFile"); byte[] data = SignedDoc.readFile(new File(inFile)); Log.d("Encrypting file:", "paso readFile"); df.setBase64Body(data); Log.d("Encrypting file:", "paso setBase64Body"); byte[] inData = m_sdoc.toXML().getBytes("UTF-8"); Log.d("Encrypting file:", "paso toXML()"); Log.d("Encrypting file", "Content: " + inFile + " size: " + data.length); Log.d("Encrypting file", "DF: " + new String(inData)); m_cdoc.setData(inData); m_cdoc.setDataStatus(EncryptedData.DENC_DATA_STATUS_UNENCRYPTED_AND_NOT_COMPRESSED); m_cdoc.addProperty(EncryptedData.ENCPROP_FILENAME, inFile + ".ddoc"); m_cdoc.setMimeType(EncryptedData.DENC_ENCDATA_TYPE_DDOC); StringBuffer sb = new StringBuffer(); sb.append(fIn.getName()); sb.append("|"); sb.append(new Long(fIn.length()).toString() + " B|"); sb.append("application/unknown|"); sb.append("/" + fIn.getName()); m_cdoc.addProperty(EncryptedData.ENCPROP_ORIG_FILE, sb.toString()); //m_cdoc.addProperty(EncryptedData.ENCPROP_ORIG_SIZE, new Long(inData.length).toString()); int nCompressOption = 0; m_cdoc.encrypt(nCompressOption); // genera el archivo cifrado en /data/data/ve.gob.cenditel/files //FileOutputStream fos = openFileOutput(outFile, Context.MODE_WORLD_WRITEABLE); outFile = encrypted_dir_files + fIn.getName()+".cdoc"; Toast.makeText(getApplicationContext(), "outFile: " + outFile, Toast.LENGTH_SHORT).show(); FileOutputStream fos = new FileOutputStream( outFile ); Log.d("Encrypting file", "antes de escribir archivo " + outFile); fos.write(m_cdoc.toXML()); Log.d("Encrypting file", "despues de escribir archivo " + outFile); fos.close(); Log.d("Encrypting file", "despues de cerrar archivo " + outFile); Toast.makeText(getApplicationContext(), "Cifrado correctamente: " + outFile, Toast.LENGTH_SHORT).show(); } catch(Exception e) { Log.d("Error encrypting file: ", inFile + " - " + e.getMessage()); e.printStackTrace(System.err); Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show(); showDialog(getResources().getString(R.string.msg_encryption_error), e.getMessage()); return; } // lanzar la actividad para mostrar el resultado del cifrado showEncryptionResults(fileToEncrypt, outFile, recipient); } // fin de selectRecipientCertificate() /** * Chequea la disponibilidad del directorio de /TibisayMovil/CertificatesToEncrypt * @return boolean */ private boolean checkCertificatesDirectoryAvailability() { // verificar acceso al directorio /mnt/sdcard/TibisayMovil/EncryptedFiles boolean mExternalStorageAvailable = false; boolean mExternalStorageWriteable = false; String state = Environment.getExternalStorageState(); String certificatesDir = Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + getResources().getString(R.string.app_name) + "/" + getResources().getString(R.string.encrypted_dir_files) + "/"; AlertDialog.Builder builder = new AlertDialog.Builder(SelectCertificateToEncryptActivity.this); if (Environment.MEDIA_MOUNTED.equals(state)) { // We can read and write the media mExternalStorageAvailable = mExternalStorageWriteable = true; Toast.makeText(getApplicationContext(), "We can read and write the media", Toast.LENGTH_SHORT).show(); // Crear directorio CertificatesToEncrypt donde se almacenan los certificados de // destinatarios para cifrado /* String certificatesDir = Environment.getExternalStorageDirectory() + "/" + getResources().getString(R.string.app_name) + "/" + getResources().getString(R.string.certificates_dir) + "/"; */ if (prepareDirectory(certificatesDir)){ return true; }else{ builder.setMessage("No existe el directorio "+certificatesDir+" para almacenar certificados.").setTitle("Error:"); } } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { // We can only read the media mExternalStorageAvailable = true; mExternalStorageWriteable = false; Toast.makeText(getApplicationContext(), "We can only read the media", Toast.LENGTH_SHORT).show(); builder.setMessage("Directorio "+certificatesDir+ " montado de solo lectura. No se pueden almancenar certificados.").setTitle("Error:"); } else { // Something else is wrong. It may be one of many other states, but all we need // to know is we can neither read nor write mExternalStorageAvailable = mExternalStorageWriteable = false; Toast.makeText(getApplicationContext(), "we can neither read nor write", Toast.LENGTH_SHORT).show(); builder.setMessage("Directorio "+certificatesDir+ " no está disponible. No se pueden almancenar certificados.").setTitle("Error:"); } builder.setNegativeButton("Cancelar", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { // User cancelled the dialog SelectCertificateToEncryptActivity.this.finish(); } }); AlertDialog dialog = builder.create(); dialog.show(); return false; } // fin de checkCertificatesDirectoryAvailability /** * Prepara directorio * @return boolean */ boolean prepareDirectory(String dir) { try { if (makedirs(dir)) { return true; } else { return false; } } catch (Exception e) { e.printStackTrace(); Toast.makeText(this, "Could not initiate File System.. Is Sdcard mounted properly?", Toast.LENGTH_LONG).show(); return false; } } /** * Crea directorio utilizando la variable tmpDir * @return boolean */ private boolean makedirs(String dir) { //File tempdir = new File(extractedDirFiles); File tempdir = new File(dir); if (!tempdir.exists()) tempdir.mkdirs(); return (tempdir.isDirectory()); } /** * Crea un dialogo con el titulo y mensaje como argumentos y lo despliega * * @return void */ public void showDialog(String title, String msg) { // 1. Instantiate an AlertDialog.Builder with its constructor AlertDialog.Builder builder = new AlertDialog.Builder(SelectCertificateToEncryptActivity.this); // 2. Chain together various setter methods to set the dialog characteristics builder.setMessage(msg) .setTitle(title); builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { // User clicked OK button Toast.makeText(getApplicationContext(), "User clicked OK button", Toast.LENGTH_LONG).show(); finish(); // lanzar el activity EncryptionCertificatesActivity } }); // 3. Get the AlertDialog from create() AlertDialog dialog = builder.create(); dialog.show(); } /** * Muestra la actividad de información del proceso de cifrado * * @return void */ public void showEncryptionResults(String fileToEncrypt, String encryptedFile, String recipient) { // lanzar el activity EncryptionResultActivity Intent intent = new Intent(this, EncryptionResultActivity.class); intent.putExtra("fileToEncrypt", fileToEncrypt); intent.putExtra("encryptedFile", encryptedFile); intent.putExtra("recipient", recipient); startActivity(intent); } }