Posts Tagged html
Filtrando datos con jQuery
Posted by Gazer in Programación on 25/06/2010
Filtrar elementos dentro de una lista o una tabla para realizar una búsqueda inline con jQuery es bastante simple, solo basta entender un poco donde va cada cosa. La función en cuestión que nos permite hacer esto es filter() que junto con un poco de trabajo para hacer un deep-search dentro del DOM nos da esta funcionalidad.
Por ejemplo si queremos mostrar los elementos de una lista que coinciden con una búsqueda deberíamos hacer algo como :
v = 'some word'; /* Ocultamos todos los LI */ $('#list ul li').hide(); /* Filtramos y mostramos los que coinciden */ $('#list ul').contents().filter(function () { return innerSearch(this, v); }).show();
La función innerSearch la pueden ver en el ejemplo, y básicamente hace un recorrido por el DOM y devolviendo true en aquellos tags donde su contenido de texto contiene el patrón buscado.
Eso nos da muchas posibilidades, ya que por ejemplo en lugar de un simple show se podría aplicar alguna clase CSS para resaltar, modificar el color o lo que se les pueda ocurrir.
Por razones de performance no es muy útil para un DOM muy complejo, pero para el caso donde yo lo necesité funciona aceptablemente bien.
Dejo un ejemplo completo con filtrado en listas y tablas.
HTML5 : Guardar el contenido de <canvas> en el servidor
Posted by Gazer in Programación on 13/04/2010
Hoy tenía ganas de hacer algo distinto (vamos, no quería trabajar
) así que me puse a jugar con HTML5, entre otras cosas con el tag <canvas> para poder dibujar. Luego de bajar varios ejemplos y tener un ‘paint’ andando lo que quería era guardar la imagen, y llegué a este post donde el autor deja guardar en PNG, JPG hasta incluso en BMP el contenido del canvas.
Pero que el usuario se pueda guardar la imagen no era mi idea, era más bien guardarle en el servidor. Por ejemplo para hacer una firma digital y usarla después en el sitio para firmar los posts como si fueran documentos
.
Al principio pensé que iba a ser super complicado, pero me encontré que todo fue mucho más fácil de lo que imaginé. Así que vamos por partes.
Vamos a empezar por el server. Como era muy poco código para este ejemplo, hice una aplicación en Sinatra que me permite mostrar un canvas y luego hacer un POST con los datos. Es ideal en este caso, ya que el server queda de tan solo unas 20 líneas de código :
require 'sinatra' require 'RMagick' get '/' do erb :index end post '/' do # Ya completaremos ... end
Como se puede ver tenemos una vista en el root y el POST lo manejamos también en la raiz. Para procesar la imagen decidí usar la única gema que conozco, RMagick, que buscando en la documentación de ImageMagick me encontré con grata sorpresa que sale leer ‘Base64-encoded inline image’ , que resulta que es justo el formato en que se obtienen los datos desde el canvas
. La única diferencia es que hay que preceder el string con ‘inline:’ y ya estamos, nuestro método POST queda así :
post '/' do data = 'inline:' + request.body.read begin image = Magick::Image.read(data).first image.write('image.png') "alert('Image saved successfully')" rescue "alert('Image format not recognized')" end end
Habría que revisar la documentación y bugs de ImageMagick para ver que tipos de implicancia puede llegar a tener en la seguridad del sitio o del sistema, pero son cosas que no vienen al caso
.
La vista (reducida para el ejemplo) puede resumirse en el siguiente HTML :
<canvas id="example" width="200" height="200">
This text is displayed if your browser does not support HTML5 Canvas.
</canvas>
<input type="button" id="submit" value="Submit" />Y un poco de javascript :
<script type="text/javascript"> $(function () { $("input").click(function () { // jQuery todavía no habla bien con HTML5, hack para // no usar un plugin. var c = $("#example").get(0); $.post('/', c.toDataURL(), null, "script"); }); // Un dibujito estático para probar var example = document.getElementById('example'); var context = example.getContext('2d'); context.fillStyle = "rgb(255,0,0)"; context.fillRect(30, 30, 50, 50); }) </script>
Y ya estamos, al presionar el botón se envían los datos de la imagen dibujada, si está todo bien ImageMagick creará el archivo en el filesystem y por último devolverá algo de javascript para informar al usuario como salió todo. Obviamente si tuviéramos un sistema de usuarios en el server podríamos guardar la imagen para cada uno, pero de nuevo, no viene al caso.
El resultado final :

$ identify -verbose image.png Image: image.png Format: PNG (Portable Network Graphics) Class: DirectClass Geometry: 200x200+0+0 Resolution: 72x72 Print size: 2.77778x2.77778 Colorspace: RGB Depth: 8/1-bit Histogram: 37500: ( 0, 0, 0, 0) #00000000 none 2500: (255, 0, 0,255) #FF0000 red Page geometry: 200x200+0+0 Compression: Zip Properties: create-date: 2010-04-13T00:20:15-03:00 modify-date: 2010-04-13T00:20:15-03:00 signature: 0a42f3c85d6364e38f14dac554d26c62a90b84b06ac7f22264c9d964657ba8d6 Tainted: False Filesize: 503b Number pixels: 39.1kb Version: ImageMagick 6.5.1-0 2009-08-27 Q16 OpenMP http://www.imagemagick.org
Probado en :
- Chromium 5.0.372.0 (44042) Ubuntu
- Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.9) Gecko/20100401 Ubuntu/9.10 (karmic) Firefox/3.5.9
Código completo : html5_canvas_submit
Limpiando los mails de Yahoo Groups
Una de las cosas más molestas que tiene Yahoo Groups es la cantidad de basura que le mete a los emails que llegan desde el grupo. Como dicen, una imagen dice más que mil palabras :
Es realmente perturbante, sobre todo porque lo pone en cada email. La primer opción que busqué fue decirle a Gmail que me muestre los emails como plain-text, lo que no encontré. Después recordé que como uso Gmail para trabajar, me llegan emails con links en html-only :S, por lo que de todas formas no me servía.
Entonces dije “no hay drama, lo modifico con Stylish“, una extensión de Firefox que permite mediante CSS cambiar cosas (y un poco más liviana que Greasemonkey). La cosa no fue tan fácil, ya que el HTML que inserta Yahoo no tiene ni class ni id en los tags HTML, por lo que tuve que hacer un poco de magia con los CSS Selectors de Firefox, que por fortuna son varios
.
El resultado final obtenido es :
Todavía quedan algunos detalles, como sacar una imagen de 1×1 pixels al final del cuerpo que según parece usa Yahoo para geolocalizar desde donde se leen sus email.
El CSS aplicado :
@namespace url(http://www.w3.org/1999/xhtml); @-moz-document domain(mail.google.com) { .ii > div > div > div > div > div + div { display: none !important; } .ii > div > div > div > div { display: none !important; } .ii > div > div > :first-child { width: 95% !important; } .ii > div > div > div > :first-child { display: block !important; width: 100% !important; } }
Edit In Place con Prototype
Una de las cosas que me venían pidiendo en ¡Falta Uno! era que se le pudieran asignar nombre a los equipos de un partido. En un principio pensé solo en poner los campos en el formulario de “crear partido” pero después me pareció que quedaba piola que se puedan editar directamente desde el resumen, usando un “Edit in place”. Me puse a buscar si había algo hecho con Proptotype (que es lo que uso en este proyecto) y encontré esto que viene con varios ejemplos.
La biblioteca es muy fácil de usar y bastante flexible en cómo queremos que se comporte el edit (puede ser un input, un textarea, un combo). Suponiendo que los nombres de equipos estén siendo mostrados de la siguiente manera :
<h2 id="team_name_1"><%= h(@match.team[0].name) %></h2> <!-- skip --> <h2 id="team_name_2"><%= h(@match.team[1].name) %></h2>
Para poder editar los títulos simplemente basta con ejecutar el siguiente código cuando se carga la página :
$('team_name_1').editInPlace({ auto_adjust: true, select_text: true, save_url: '<%= changename_match_path(@match, :team => 1) %>' }); $('team_name_2').editInPlace({ auto_adjust: true, select_text: true, save_url: '<%= changename_match_path(@match, :team => 2) %>' });
Es recomendable poner este código dentro de un método y usar un Observer para ejecutarlo, así mantenemos separada la lógica JS del HTML. Bastaría con un simple Event.observe(window, 'load', initEIP);.
Por el lado del servidor, el método que atiende el request (el definido el save_url) tiene que devolver el nuevo valor que va a tomar el campo. Por ejemplo, si el nombre no se pudo cambiar, deberíamos devolver el anterior. En este caso que es simple el template a devolver es el siguiente :
<%= h(@team.name) %>
Para terminar, en caso de que el navegador del usuario no tenga JS queda el formulario de “Editar/Crear Partido” donde se pueden poner los nombres de manera tradicional.
Sobreviviendo ataques
Está terminando un día largo, de esos que uno espera que no le toquen, pero que tarde o temprano llegan. Ayer a la noche en 3DG fuimos víctimas de un pequeño ataque. Por suerte los atacantes super buena onda. Luego de que apagamos el primer incendio estuvimos chateando con ellos y nos dieron la data de por donde entraron, cómo, qué cosas modificaron y lo mejor de todo, donde nos habían dejado los backups que habían hecho
.
El ataque consistió en hacer que nuestros sitios (el target era el foro que es el que tiene más tráfico, pero afectó a otros sitios también) sean redirigidos a una página muy graciosa que no pienso linkear porque no es ATP. Para lograrlo (ya que el foro está aislado y no pudieron entrar por ahí) nos crackearon el sistema de publicidad e insertaron un banner javascript que hacía el redirect. Simple y efectivo.
Para lograr el acceso al server de ads fue más fácil, simplemente explotaron un SQL Injection que por la fecha de última modificación del script, estaba desde el 2001
. Con eso consiguieron el password de admin para poder poner su publicidad. Nuestro segundo problema fue obvio, el usuario que usa ese script para acceder a la DB tenía demasiados privilegios y pudo leer y modificar una otra base de datos.
Más allá del trabajo que tuvimos que hacer para recuperar de nuestros backups cosas por las dudas (aunque nos hicieron backups tampoco confiar a ciegas
) tuvimos que empezar a auditar cosas que teníamos pendiente hace rato. Para empezar necesitamos bajar los servicios completamente y la forma más linda que encontré fue usando un rewrite rule de apache, como sigue :
RewriteEngine on RewriteCond %{REQUEST_URI} !^/imagenes RewriteCond %{DOCUMENT_ROOT}/maintenance.html -f RewriteCond %{REQUEST_URI} !/maintenance.html$ RewriteRule $ /maintenance.html [R=302,L]
De esta manera cuando terminamos de hacer el mantenimiento simplemente borramos el maintenance.html y el sitio vuelve solo a la vida. De paso ya lo dejamos para cuando hagamos futuros updates.
Lo otro que nos entró en duda cuando arreglamos el problema fue : ¿lo arreglamos realmente? ¿tendremos otro agujero en algún lado?. Para poder revisar esto comencé a buscar herramientas para auditar SQL Injections y me encontré con un post donde habían varias soluciones. La que usamos finalmente fue sqlmap porque fue la que mejor nos pareció que andaba.
Fue una tarde divertida viendo que podíamos romper de nuestro viejo sitio. Para escanearlo simplemente corríamos :
#$ sqlmap -dbs -u "http://127.0.0.1/scriptbuggeado.php?Id=1"El programa primero trata de ver si el parámetro Id es vulnerable a diferentes formas de hacer injection y si descubre alguna trata de obtener la lista de DBs. Es lindo ver cuando aparecen todas tus DBs en la consola
. Si le agregamos “-v 2″ es más gracioso aún, porque los nombres van apareciendo letra a letra (parece que las va adivinando o algo, no me fijé en el código para ver como lo hace).
A esta hora cerramos ya el agujero del ataque y dos más que detectamos.
El último problema que encontramos fue que habían subido un shell. Para esto crackearon el password de programa para enviar newsletters y subieron un archivo php que tiene un shell re lindo que tiene funciones para escanear vulnerabilidades localmente. Acá el problema fue que el sysadmin anterior dejó permiso para ejecutar script en el directorio donde el programa guarda attachments que después se usan en el email (como imágenes en esos emails molestos HTML que nos llegan todos los días). Sacando los permisos para ejecutar cualquier tipo de script el shell ya no funciona.
Como sysadmin “temporal” fue una experiencia divertida, sobre todo porque no hubo pérdida de datos y la buena onda de los atacantes
(¿tendré el Síndrome de Estocolmo?).


