Leer y escribir archivos locales en Flex

Sí, has leído bien, en este post voy a explicar cómo leer y escribir archivos en el lado del cliente con Flex, ya sé que el nivel de seguridad de Adobe Flash no lo permite, pero… ¡cuántas puertas se nos abrirían si pudieramos hacerlo!

Seguridad en Flash Player

Antes de nada me gustaría indicar que la traducción informática de sandbox sería: entorno limitado y protegido donde las aplicaciones pueden ejecutarse sin riesgo de dañar el sistema. Como creo que hay traducciones al castellano que son peores que las propias palabras anglosajonas y este caso es uno de ellos voy a utilizar la palabra original, así mismo, voy a usar algunas otras palabras sin traducir puesto que supongo que a la persona que lo está leyendo le va a ser más familiar el término sin traducción.

Security sandboxes

El PC cliente puede obtener(cargar) SWFs de distintas fuentes, por ejemplo de una página web o de su propio disco duro. Flash Player asigna de forma individual a cada SWF así como a otros recursos como objetos compartidos, bitmaps, sonidos, videos, etc. unos entornos de seguridad basados en el origen de su procedencia al cargarse en el Flash Player.

Remote sandboxes

Flash Player clasifica los assets (incluyendo SWFs) procedentes de Internet en sandboxes separados que corresponden a sus dominios de origen. Por defecto estos ficheros son autorizados a acceder a cualquier recurso de su propio servidor (dominio). A los SWFs remotos también se les puede permitir acceder a datos adicionales de otros dominios por autorización explícita de éstos o por la autorización del autor como los archivos cross-domain policy y el método Security.allowDomain(). Para más detalles ver Website controls (cross-domain policy files) y Author (developer) controls.Los SWFs remotos no pueden cargar ningún archivo ni recurso local.

Para más información ver el libro blanco de seguridad del Flash Player 9.

Local sandboxes

Este tipo de sandbox se refiere a los SWFs que cargamos de forma local mediante el protocolo “file:”, por ejemplo file:///miflash.swf.

Los SWFs locales son ubicados en uno de los tres siguientes sandboxes:

  • local-with-filesystem sandbox Flash Player ubica todos los SWFs locales y assets en este sandbox por defecto. Desde este sandbox los SWFs pueden leer archivos locales (utilizando la clase URLLoader por ejemplo), pero no se pueden comunicar con la red de ninguna manera. Esto asegura que los datos locales del usuario no puedan ser propagados por la red o compartidos de otra forma inapropiada.
  • local-with-networking sandbox Son los SWFs que se generan cuando al ser compilados se especifica que puede tener acceso a la red si se ejecutan de forma local (ver Setting the sandbox type of local SWF files) Estos SWFs no pueden tener acceso a los archivos locales, sí a los archivos de Internet, pero siempre y cuando el servidor tenga configurado un archivo cross-domain policy o utlice el método Security.allowDomain(“*”).
  • local-trusted sandbox Estos SWFs son registrados como de confianza bien por el usuario o por programas de instalación, pueden interactuar con otros SWFs y pueden leer datos de cualquier parte (local o remota).

La comunicación entre los sandboxes local-with-networking y local-with-filesystem así como la comunicación entre local-with-filesystem and sandboxes remotos está estrictamente prohibida y no se puede establecer ningún tipo de permiso por el usuario o por el administrador.

El scripting en cualquiera de las dos direcciones entre archivos HTML locales y SWFs locales (utilizando por ejemplo la clase ExternalInterface) requiere que tanto el HTML como el SWF se encuentren en el local-trusted sandbox. Eso es así porque los modelos de seguridad local de los navegadores difieren del modelo de seguridad local del Flash Player.

Los SWFs del local-with-networking sandbox no pueden cargar SWFs en el local-with-filesystem sandbox.

Los SWFs del local-with-filesystem sandbox no pueden cargar SWFs en el local-with-networking sandbox.

Bien, leída esta traducción del modelo seguridad del Flash Player nos deja bien claro que si tenemos acceso a los arhivos locales no tenemos acceso a la red y si tenemos acceso a la red no tenemos acceso a los archivos locales, pero, qué ocurriría si el accesoa los datos locales pudieran ser realizados por el contenedor del SWF, es decir por el archivo HTML, éstos archivos pueden contenerJavascript, es ahí en donde nos vamos a centrar a continuación.

Accediendo a datos locales en Javascript desde Firefox

En Firefox tenemos una jugosa opción a la hora de programar que es XPConnect, ésta es una capa dentro del XPCOM (Cross Platform Component Object Model) que viene a ser la opción equivalente a los COM (ActiveX) de Microsoft, pero con la ventaja de ser multi-plataforma; el XPConnect permite la interoperación entre XPCOM y lenguajes de script como Javascript.

De esta forma tenemos la posibilidad de solicitar al usuario un nombre y ubicación de un archivo tanto para abrir como para grabar, leer y grabar datos locales del usuario, tanto de su disco duro como de su red interna, estos son los los recursos que vamos a necesitar del XPCOM para el propósito de este artículo.

Veamos un ejemplo de lectura de datos con XPConnect:

// Solicitamos privilegios al navegador
netscape.security.PrivilegeManager.enablePrivilege(“UniversalXPConnect”);

// Creamos un puntero al archivo local
var file = Components.classes[“@mozilla.org/file/local;1”].createInstance(Components.interfaces.nsILocalFile);file.initWithPath( filePath );
if(!file.exists()) return null;

// Creamos un stream de lectura
var inputStream = Components.classes[“@mozilla.org/network/file-input-stream;1”].createInstance(Components.interfaces.nsIFileInputStream);inputStream.init(file,0x01,00004,null);

// Leemos el archivo
var sInputStream = Components.classes[“@mozilla.org/scriptableinputstream;1”].createInstance(Components.interfaces.nsIScriptableInputStream);sInputStream.init(inputStream);var content = sInputStream.read(sInputStream.available());

Esta opción es perfecta, pero tiene un pequeño problema, que topamos con la seguridad de Firefox a la hora de utilizar el XPConnect, por defecto nos va a denegar su utilización y el script no se va a ejecutar, para solucionar esto tenemos dos opciones, la de pago y la de no pago, si alguien conoce alguna otra por favor que lo comparta con nosotros.
Primera opción:

Asociar el script a una firma digital

La primera opción es obtener una firma digital y asociarla al script, en Firefox una página HTML y los scripts que incluye usando la etiqueta <SCRIPT src=”…”> son firmados y ubicados en un archivo JAR junto con su firma asociada. Para ejecutar dicho HTML se utiliza el protocolo “jar:” por ejemplo: “jar:http://www.site.com/myjar.jar!/signed.html” la firma está asocia automáticamente al script y éste se verifica como parte de la página web a cargar. El coste anual aproximado de cada firma digital si no me equivoco es de unos 330 Euros (500 dólares). Para saber más al respecto podéis visitar la siguiente dirección Signed Scripts in Mozilla.
Segunda opción:

Hacer que Firefox acepte scripts sin firmar

La segunda opción es menos elegante pero no cuesta un céntimo, implica la intervención del usuario o del administrador. En Firefox existe un parámetro de configuración que podemos modificar fácilmente para que nos lo permita ejecutar scripts sin firmar se trata de “signed.applets.codebase_principal_support“, es de tipo boolean y por defecto contiene “false”, el usuario deberá establecerlo a “true” y para acceder a la modificación seguimos los siguientes pasos:

  • En Firefox introducir lo siguiente en la barra de direcciones: about:config
  • Aparecerá una lista de parámetros, buscar la preferencia “signed.applets.codebase_principal_support
  • Modificar el valor a “true” haciendo doble click sobre ella.

bombilla Aquí tenéis un video demostrativo.

Por otra parte, también en la solicitud de privilegios Firefox va a mostrar un mensaje al usuario indicando que un script ha solicitado los privilegios ejecutar o instalar programas en la máquina y nos pregunta si queremos permitir estos privilegios, para proceder debemos permitirlo y tenemos la opción de marcar un checkbox para que no nos vuelva a hacer la misma pregunta para el dominio en curso, si ejecutamos el mismo script en otro dominio Firefox nos volverá ha hacer la misma pregunta.

bombilla Ver vídeo.

Si aceptamos los privilegios de forma permanente Firefox almacenará unos datos en el archivo “prefs.js“, por ejemplo:


user_pref(“capability.principal.codebase.p2.granted”, “UniversalXPConnect”);
user_pref(“capability.principal.codebase.p2.id”, “http://flex.diaztorres.com”);
user_pref(“capability.principal.codebase.p2.subjectName”, “”);

Si deseamos que Firefox vuelva a preguntar al usuario simplemente eliminamos esas tres líneas del archivo, eso sí debemos eliminarlas cuando Fierfox esté cerrado, puesto que cuando se cierra actualiza este archivo automáticamente.

Lo primero que se nos viene a la mente es que esto no es lo recomendable ni lo recomendado para cualquier usuario, puesto que puede suponer un potencial grave riesgo tanto para la seguridad de nuestro sistema operativo como para la confidencialidad de nuestros datos, cierto, luego recomiendo que esta opción la toméis sólo en cuenta si el entorno sobre el cual vais a actuar va a ser un entorno controlado como una Intranet.

Accediendo a datos locales en Javascript desde Internet Explorer

En Internet Explorer (IE) para conseguir nuestro propósito utilizamos varios ActiveX, esencialmente el ADODB.Stream, pero por defecto como ocurre en Firefox, no podemos utilizarlos si el navegador no está correctamente configurado; la configuración consiste esencialmente en añadir el dominio a la lista de sitios de confianza y personalizar el nivel de seguridad asignando más privilegios a esta zona: (Activar) Inicializar y activar la secuencia de comandos de los controles de ActiveX no marcados como seguros.

bombilla En este enlace tenéis un video demostrativo de la configuración en IE.

Llamando a las funciones Javascript desde Flex

Para que podamos ejecutar funciones Javascript desde Flex el parámetro “AllowScriptAccess” del <OBJECT> embebido en el HTML debe permitirlo, este parámetro puede tener tres valores:

  • sameDomain“, indica que las llamadas a Javascript se permiten si el SFW y la página web están en el mismo dominio.
  • never“, indica que en ningún caso se permiten las llamadas.
  • always“, indica que las llamadas a las funciones siempre se permiten.

El valor por defecto de AllowScriptAccess es “sameDomain”.

Ejemplo:

<object id=’MyMovie.swf’ classid=’clsid:D27CDB6E-AE6D-11cf-96B8-444553540000′ codebase=’http://download.adobe.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0′ height=’100%’ width=’100%’>
<param name=’AllowScriptAccess’ value=’sameDomain‘/>
<param name=’src’ value=”MyMovie.swf’/>
<embed name=’MyMovie.swf’ pluginspage=’http://www.adobe.com/go/getflashplayer’ src=’MyMovie.swf’ height=’100%’ width=’100%’ AllowScriptAccess=’sameDomain’/>
</object>

El paquete flash.external contiene la clase ExternalInterface que nos permite comunicarnos con el contenedor del Flash Player, en este caso una pagina HTML con Javascript. Dada la sencillez de esta clase creo que no requiere ningún tipo de explicación así que bastará con un simple ejemplo:

Archivo HTML:

<script>
function jsTest(param){
alert( param );
return ‘ok’;
}
</script>

Archivo Flex:

trace( ExternalInterface.call(“jsTest”, “texto de alerta” ) );

Funciones Javascript “M á g i c a s”

Si el XPCOM es el alma de este post, las funciones Javascript son el cuerpo que le da la forma. He creado unas funciones para:

  • solicitar un archivo al usuario
  • leer archivos de texto
  • leer archivos binarios
  • grabar archivos de texto
  • grabar archivos binarios
  • lanzar (ejecutar) archivos locales

La inclusión de las funciones en el HTML puede ser realizada de dos formas:

  1. Mediante la carga de un archivo externo:

    <script src=”localfile.js” language=”javascript”></script>

    Esta línea de código la podemos incluir directamente en el archivo index.template.html de la carpeta html-template que tenemos en nuestro proyecto.

  2. Inyectando las funciones Javascript desde Flex al contenedor HTML, esto lo podéis ver explicado en el Blog de Abdul Qabiz es una fórmula muy interesante si no quereis que cualquier usuario vea vuestro Javascript, aunque te todas formas es fácilmente hackeable por un experto.

Ejecutando el ejemplo

Si has seguido los pasos correctamente (link al video) ahora estás en disposición de ejecutar el ejemplo que he realizado para MadeInFlex, está compilado con la versión Flex 3 Beta 3 y tiene activa la opción “view source”.

star Enlace al ejemplo
star Enlace al código fuente
starEnlace a localfile.zip

Conclusión

Creo que la opción de poder leer y grabar archivos en el lado del cliente abre a Flex multitud de posibilidades que, bien empleadas pueden hacer aún mas “ricas” lo que denominan Rich Internet Applications (nombre que si se me permite me parece bastante desafortunado) en entornos controlados como son las Intranets Corporativas.

19 Comentarios

  1. Pingback: Leer y escribir archivos locales en Flex

  2. Enrique Duvos

    El acronimo RIA engloba Internet, Extranet, Intranet. Quizas en su momento se deberia haber pensado en algo mas como RWA ( Rich Web Application ) pero la industria ya tiene muy asimilado que el termino RIA no se centra unica y exclusivamente en entornos Internet puros.

    E-

  3. paco

    oye me podrian decir que es miflash.com lo que pasa es que se lo borre ami computadora y ya no quiso trabajar despues de eso

  4. Eduardo

    Sigo sin entender la parte de flex y su uso por favor me encanta todas las maravillas que dices que hace pero donde parto, donde comienzo, HELLLLLLLLLP!

  5. Raul Diaz

    Eduardo, entiendo que lo que preguntas es cómo comienzas a aprender Flex. Hay pululando por la red multitud de tutoriales y ejemplos, lamentablemente la mayoría de ellos en inglés, si buscas aquí en madeinfex seguro que encuentras alguno, también puedes acudir a flex.org, desde allí encontrarás muchisima información.

  6. Pablo

    En el caso del ejemplo, que usas para generar el Excel ? (para PDF usas AlivePDF), cuando me bajo el fuente no me baja las librerias.
    Muchas gracias. Saludos,

  7. Pablo

    Raul, muchas gracias por contestarme.
    He visto que existen varias soluciones en la web (app flex en un archivo excel, html con un owc de excel, enviar csv a un servlet y cambiar content, servicio java que genera excel), pero una libreria como alivePDF pero para excel seria la mejor solucion.
    Si es que aun no la has podido terminar o probar y necesitas una mano, avisame por favor q con gusto te ayudaré.
    Gracias nuevamente.
    Saludos,

  8. Pablo

    Raul, como estas ?
    Cuando agrego imagenes en el PDF (usando addImage o addImageStream), no funciona la solución.
    Aparentemente da un error de javascript al guardar el pdf (saveFile) o ni siquiera llega a a entrar en esa funcion, puse alerts que me indique por donde va y no ejecuta ni el primero, y no me devuelve ningun error con el getLastError(). Cuando le saco la imagen al PDF vuelve a funcionar todo correctamente.
    Saludos,

  9. ernesto

    alguien sabe si sigue funcionando
    netscape.security.PrivilegeManager.enablePrivilege(“UniversalXPConnect”);

    para las nuevas versiones de firefox o se tenga que hacer algo mas??

    Saludos

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Acerca de Made In Flex

Made In Flex es una comunidad de desarrolladores de Apache Flex creada en 2006.

Apache Flex, anteriormente conocido como Adobe Flex, es un SDK (kit de desarrollo de software) para crear aplicaciones enriquecidas - multiplataforma basadas en Adobe Flash donado por Adobe a la fundación Apache in 2011 y promocionado a proyecto de primer nivel en Diciembre de 2012.

Actualmente estamos cambiando muchos aspectos del sitio web para ofrecer un sitio útil para toda la comunidad que tenga en cuenta las necesidades actuales.

Últimas Fotos

Instalador de Apache Flex

Entrar o Registrase