
Three Eyed Smile

OpenVPN es una solución multiplataforma que ha simplificado la configuración de VPNs en contra de soluciones más antiguas y difíciles de configurar como IPSec, haciéndolo más accesible para el público con menos experiencia en este tipo de tecnologías, permitiéndonos así crear nuestro propio servidor VPN.
Lo primero que tenemos que hacer para crear nuestro propio servidor VPN es, obviamente, conseguir un servidor dónde realizar la instalación. Existen múltiples opciones en la nube y la mayoría de ellas, además, cuentan con imágenes para poder preinstalar OpenVPN en la creación de los servidores. Entre las posibles opciones que podemos utilizar encontramos los siguientes:
También podríamos realizar la instalación en cualquier máquina Ubuntu con acceso a internet, como un ordenador antiguo o una Raspberry Pi. En estos casos deberemos realizar además tareas de redireccionamiento de tráfico en nuestra red local para que todo funcione correctamente.
Para instalar OpenVPN en Ubuntu podemos utilizar apt-get mediante el siguiente comando:
sudo apt-get install openvpn easy-rsa
Después de esto, tenemos que extraer el fichero de ejemplo de configuración en la carpeta /etc/openvpn para incorporarlo así a nuestra configuración. Esto se puede hacer con un solo comando:
gunzip -c /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz > /etc/openvpn/server.conf
Una vez extraído editamos el fichero server.conf y realizamos algunos cambios.
sudo nano /etc/openvpn/server.conf
Las modificaciones más importantes a realizar son descomentar algunas líneas eliminando el caracter ‘;’. Para que el servidor VPN pase el tráfico web de los clientes a su destino, debemos descomentar la siguiente línea:
push "redirect-gateway def1 bypass-dhcp"
Es importante utilizar el servidor OpenDNS con los clientes conectados para la resolución de DNS. Esto puede ayudar a evitar que las solicitudes de DNS se escapen fuera de la conexión VPN. Sin embargo, es importante especificar también estos servidores DNS en los dispositivos de los clientes.. Para lograrlo necesitamos descomentar las siguientes líneas:
push "dhcp-option DNS 208.67.222.222" push "dhcp-option DNS 208.67.220.220"
Para evitar que OpenVPN se ejecute en modo root descomentaremos las siguientes líneas que especifica el usuario nobody como el usuario por defecto a utilizar. Nobody es un usuario sin los privilegios por defecto de un usuario normal.
user nobody group nogroup
El siguiente paso es configurar el reenvío de paquetes con sysctl. Esto le indicará al núcleo del servidor que reenvíe el tráfico de los dispositivos cliente hacia Internet. De lo contrario, el tráfico se detendrá en el servidor. Para lograrlo debemos ejecutar este comando:
echo 1 > /proc/sys/net/ipv4/ip_forward
Para hacer que este cambio sea permanente debemos descomentar la siguiente línea en el fichero /etc/sysctl.conf.
net.ipv4.ip_forward=1
De forma predeterminada, las reglas de reenvío de Linux eliminan todos los paquetes que intentan acceder a otra interfaz, por lo que necesitamos configurar un cortafuegos que permita el tráfico a través del puerto VPN 1194 y enviar por defecto las peticiones realizadas a Internet por los clientes. Para evitar el uso de IPTables vamos a usar ufw con los siguientes comandos para permitir conexiones SSH y 1194/udp:
ufw allow ssh ufw allow 1194/udp
Después de eso, tenemos que modificar el archivo de configuración ufw para establecer la política de forward por defecto a ACCEPT. Este archivo es /etc/default/ufw y necesitamos modificar la línea:
DEFAULT_FORWARD_POLICY="ACCEPT"
Finalmente, debemos añadir unas cuantas reglas en el fichero /etc/ufw/before.rules para que OpenVPN funcione correctamente. Estas reglas son:
# START OPENVPN RULES # NAT table rules *nat :POSTROUTING ACCEPT [0:0] # Allow traffic from OpenVPN client to eth0 -A POSTROUTING -s 10.8.0.0/8 -o eth0 -j MASQUERADE COMMIT # END OPENVPN RULES
El resultado del fichero debe parecerse al de la Captura 1:
Con los cambios realizados en ufw, podemos activarlo finalmente:
ufw enable
El siguiente paso es configurar y generar los certificados que OpenVPN utilizará para cifrar el tráfico. Para este propósito vamos a utilizar los scripts de Easy RSA en nuestra carpeta de servidor.
Copiamos los scripts de generación de Easy RSA con el siguiente comando:
cp -r /usr/share/easy-rsa/ /etc/openvpn/
Creamos una carpeta para almacenar las claves:
mkdir /etc/openvpn/easy-rsa/keys
Ahora debemos modificar algunas variables en el fichero /etc/openvpn/easy-rsa/vars como la carpeta de EASY_RSA el valor del KEY_SIZE como podemos ver en la Captura 2:
Antes de crear cualquier clave necesitamos configurar nuestro servidor como CA (Certificate Authority) para firmar nuestras claves con los siguientes comandos:
cd /etc/openpvn/easy-rsa source ./vars # Carga el fichero vars editado previamente ./clean-all # Borra cualquier configuración y claves anteriores. Si ya hemos generado claves anteriormente, podemos saltarnos este comando. ./build-ca # Genera CA
Como podemos ver en la Captura 3 el sistema nos pedirá información sobre el certificado como el país, la provincia, el nombre, etc.
Con el siguiente comando generamos las claves del servidor para un servidor con nombre ‘server’ como podemos ver en la Captura 4.
./build-key-server server
Ahora que tenemos las claves en la carpeta/etc/openvpn/easy-rsa/keys/ las copiamos en la carpeta /etc/openvpn:
cp /etc/openvpn/easy-rsa/keys/{server.crt,server.key,ca.crt} /etc/openvpn
Generamos además los parámetros Diffie-Hellman. Esto puede tardar varios minutos.
openssl dhparam -out /etc/openvpn/dh2048.pem 2048
Finalmente, podemos iniciar nuestro servidor OpenVPN con el siguiente comando:
service openvpn start
Una vez generadas las claves del servidor, podemos generar claves para cada uno de los diferentes clientes que queremos conectar a nuestra VPN. No existe ninguna relación entre la clave y el propio dispositivo por lo que podríamos generar una clave de cliente única y usarla en todos los dispositivos, eso sí, sólo un cliente podría conectarse a la VPN al mismo tiempo.
Para crear credenciales de autenticación independientes para los clientes (Captura 6) necesitamos usar el script build-key de la carpeta Easy RSA:
./build-key client1
Este comando va a generar las siguientes claves:
Ahora que tenemos las claves, podemos proceder con la creación del archivo de configuración. Para ello partimos de uno de los archivos predeterminados de Easy RSA copiándolo en nuestra carpeta:
cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf /etc/openvpn/easy-rsa/keys/client.ovpn
El siguiente paso requiere descargar a nuestro equipo local las llaves del cliente, los archivos de client.ovpn y ca.cart. Podemos hacer eso con SCP:
scp root@[SERVER-IP]:/etc/openvpn/easy-rsa/keys/client1.key . scp root@[SERVER-IP]:/etc/openvpn/easy-rsa/keys/client1.crt . scp root@[SERVER-IP]:/etc/openvpn/easy-rsa/keys/client.ovpn . scp root@[SERVER-IP]:/etc/openvpn/easy-rsa/keys/ca.crt .
Una vez que hayamos descargado los archivos en nuestro ordenador, podemos crear un perfil OpenVPN unificado mediante la edición del archivo de plantilla client.ovpn e incluir la Autoridad de Certificación de los servidores, el certificado de clientes y su clave. También necesitamos hacer algunas modificaciones en el archivo:
Para combinar los archivos individuales en el único perfil unificado, el contenido de los archivos ca.crt, client1.crt y client1.key se pegan directamente en el perfil de .ovpn utilizando una sintaxis básica similar a XML. El código XML al final del archivo debe tener este formato:
<ca> -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE----- </ca> <cert> Certificate: ... -----END CERTIFICATE----- ... -----END CERTIFICATE----- </cert> <key> -----BEGIN PRIVATE KEY----- ... -----END PRIVATE KEY----- </key>
Para poder usar el archivo .opvn de configuración y conectarnos remotamente a nuestro servidor VPN podemos hacer uso de diferentes clientes VPN disponibles.
OpenVPN Connect ofrece versiones para PC, dispositivos Android e iOS. En nuestro caso vamos a utilizar otro cliente VPN para Mac OSX, llamado Tunnelblick. Una vez instalado solo necesitamos abrir nuestro archivo de perfil .ovpn y Tunnelblick configurará automáticamente la conexión VPN para que podamos utilizarla como podemos ver en Captura 8.
Podemos asegurarnos de que estamos conectados a la VPN usando cualquier servicio web para obtener nuestra IP pública como podemos ver en Captura 9 que detecta que todo está bien configurado.
En el artículo Transformaciones con XSLT vimos una introducción al lenguaje de transformaciones, sin embargo, no explicamos como utilizar debidamente esta tecnología. En este artículo explicaremos como realizar transformaciones XSLT en Python haciendo uso de la biblioteca lxml y veremos como montar un servidor web con Flask para hacer uso de nuestro procesador XSLT desde cualquier lugar.
Tanto los documentos XML como las hojas de estilo en XSLT son completamente independientes de la plataforma que se vaya a utilizar para realizar las transformaciones. Podemos enlazar una hoja de estilos XSLT a un documento XML de forma permanente añadiendo un elemento <?xml-stylesheet ..?> justo después de la declaración XML como podemos ver en el Fragmento de Código 1. De esta forma, al abrir el documento con un navegador web, éste aplicará las transformaciones pertinentes de forma automática y podremos comprobar el resultado.
<?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet type="text/xsl" href="hojaEstilos.xslt"?> <Coleccion> <documento> <titulo>El Titulo</titulo> <autor>Miguel S. Mendoza</autor> <fecha>1984</fecha> </documento> <documento> <titulo>El Otro Titulo</titulo> <autor>Marta S. Román</autor> <fecha>2016</fecha> </documento> </Coleccion>
Sin embargo, si lo que queremos es generar documentos independientes es necesario utilizar un procesador XSLT que se encargue de aplicar al documento XML las reglas de transformación incluidas en la hoja de estilo XSLT y genere un documento final. La transformación se realiza de la siguiente forma:
Afortunadamente existen procesadores XSLT para casi todos los lenguajes de programación, como Perl, C, Java, etc. En nuestro caso hemos optado por implementar el procesador haciendo uso del lenguaje Python y su librería libxml.
Python es un lenguaje muy potente y fácil de aprender. Maneja eficientes estructuras de datos de alto nivel y cuenta con un enfoque simple pero efectivo de programación orientada a objetos. Posee una sintaxis muy elegante y tipado dinámico, que junto con su carácter interpretado lo convierte en un lenguaje ideal para desarrollo rápido de aplicaciones en innumerables áreas. Python se encuentra en un gran número de aplicaciones web y de escritorio, por lo que es un lenguaje de aprendizaje casi obligatorio para un desarrollador actual, ya que permite resolver problemas de una forma muy eficiente en un corto espacio de tiempo. Además, cuenta con un repositorio de paquetes que permiten extender la funcionalidad de las aplicaciones de una forma sencilla, muy similar a como se hace con NodeJS.
El gestor de paquetes recomendado para Python se denomina pip, y se utiliza de un modo similar a npm o apt-get. Con él, podemos instalar el paquete lxml que nos permitirá procesar documentos XML y HTML de forma sencilla.
pip install lxml
En el Fragmento de Código 2 podemos ver cómo aplicar una plantilla XLST a un documento XML como el que vimos en el Fragmento de Código 1.
import lxml.etree as ET def transforma_documento(XML): dom = ET.fromstring(XML) transform = ET.XSLT(ET.parse('hojaEstilos.xslt')) nuevodom = transform(dom) resultado = ET.tostring(nuevodom, pretty_print=True) return resultado
Como podemos observar, aunque no hayamos visto el lenguaje Python hasta ahora, simplemente leyendo el código entendemos perfectamente lo que hace. Inicialmente se lee el fichero de entrada que se pasa como parámetro al método transforma_documento. Seguidamente se utiliza el contenido del fichero para obtener el árbol de nodos del documento XML y almacenarlos en la variable dom. A continuación se obtiene un objeto de transformación leyendo el fichero de hoja de estilos “hojaEstilos.xslt” en el que se han definido las transformaciones, cuyo contenido podemos ver en el Fragmento de Código 3. Se aplican las transformaciones en el árbol de nodos y se obtiene un nuevo árbol de documento que podemos convertir en una cadena de texto para devolverla como resultado para, si quisiéramos, escribirla en un nuevo fichero obteniendo finalmente nuestro fichero transformado.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> <xsl:template match="/"> <html> <body> <h1>Los Documentos</h1> <table> <tr> <th>Titulo</th> <th>Autor</th> </tr> <xsl:for-each select="Coleccion/documento"> <tr> <td><xsl:value-of select="titulo" /></td> <xsl:choose> <xsl:when test="fecha > 2010"> <td style="color: grey"> <xsl:value-of select="autor" /> </td> </xsl:when> <xsl:otherwise> <td style="color: green"> <xsl:value-of select="autor" /> </td> </xsl:otherwise> </xsl:choose> </tr> </xsl:for-each> </table> </body> </html> </xsl:template> </xsl:stylesheet>
Así, si abriéramos el fichero XML en un navegador obtendríamos un resultado parecido al que podemos observar en la siguiente captura.
Python puede instalarse en cualquier sistema operativo actual. Sin embargo, si queremos utilizar código en este lenguaje desde un entorno web se hace necesario utilizar una infraestructura apropiada que permita desarrollar aplicaciones web o servicios sin necesidad de manejar detalles de bajo nivel como protocolos o manejo de procesos e hilos.
Entre las numerosas infraestructuras que podríamos utilizar nos hemos decantado por Flask, una infraestructura web minimalista que nos permite realizar peticiones a nuestro código de transformación de forma sencilla mediante el desarrollo de una API REST. En el Fragmento de Código 4 podemos ver un ejemplo sencillo de cómo podríamos utilizar nuestro código de transformación visto en el Fragmento de Código 2 utilizándolo como una biblioteca denominada publisher, que se corresponde con el nombre del fichero en el que hemos almacenado nuestras funciones transformadoras.
import publisher from flask import Flask, render_template, request app = Flask(__name__) @app.route('/') def index(): return render_template('index.html') @app.route("/transform", methods=['POST']) def transform(): file = request.files['uploadfile'] XML = file.read() resultDocument = publisher.transforma_documento(XML) return resultDocument if __name__ == "__main__": app.run()
Para poder gestionar correctamente el servidor web, utilizamos las funciones render_template y request, con el objetivo de devolver ficheros estáticos, y de manejar las peticiones respectivamente. Como podemos observar es un código relativamente sencillo que nos permitirá obtener un documento transformado a partir de un documento que podemos enviar mediante un formulario HTML como el del Fragmento de Código 4.
<form action="/transform" method="post"> <input type="file" name="uploadfile" /> <input type="submit" value="Transformar" /> </form>
Podéis encontrar el código fuente utilizado en este artículo en GitHub.
Utilizar Flask nos permitirá, entre otras cosas, poder mejorar la modularidad de un sistema en diferentes máquinas en caso de que fuera necesario, es decir, podríamos perfectamente instalar nuestro servicio de transformaciones en un servidor, y la aplicación web que utilice éste en otro distinto. Sin embargo, si quisiéramos utilizar tanto Flask como NodeJS en una misma máquina tendremos que utilizar aplicaciones intermedias como Virtual Environment para mantener la aplicación Flask ejecutándose como servicio, uWSGI como interfaz web entre servidores web y el servicio creado con Virtual Environment y NGINX como servidor web para controlar todas las peticiones entre la aplicación web y el servicio de transformaciones en Python.
XSLT es un lenguaje que permite transformar documentos XML en cualquier otro tipo documento. Este lenguaje busca dar solución al problema de expresar información estructurada de la forma más abstracta y reutilizable posible. Como veremos más adelante, este lenguaje resulta ideal para innumerables propósitos, ya que permite realizar transformaciones con XSLT de documentos de publicaciones con contenido básico en cualquier tipo de formato de presentación, como un micro sitio con contenido adaptativo a dispositivos móviles, un PDF, o un libro en formato EPUB listo para distribuirse a través de comercios de libros electrónicos.
Comenzaremos explicando los conceptos básicos relacionados con el lenguaje para posteriormente describir la forma en la que lo vamos a utilizar, así como el tipo de procesador XSLT que implementaremos.
XSLT se nutre de dos fuentes principales para funcionar: El documento XML a transformar y la plantilla XSLT de definición de las transformaciones. Estos dos documentos son utilizados por el procesador XSLT para generar un nuevo documento. La Figura 1 muestra la relación entre estos tres elementos.
Tanto el documento XML como la hoja de estilos deben ser documentos XML válidos y bien formados, lo que significa que una hoja de estilos se puede utilizar para transformar otra hoja de estilos.
Un documento XML contiene elementos estructurados en forma de árbol definidos por medio de etiquetas rodeadas de corchetes angulares y barras (<,> y /). Para que un documento XML esté bien formado se deben seguir unas reglas básicas de estructuración de contenido. Estas reglas son las siguientes:
Para que además de bien formado, un documento XML sea válido, debe cumplir con esquemas predefinidos que establecen otras restricciones al contenido. Estos esquemas son las Definiciones de Tipo de Documento y los Esquemas XML, que vienen a ser metalenguajes utilizados para definir las características de un vocabulario XML (Doug Tidwell, XSLT.: O’Reilly, 2008). Con estos esquemas podemos definir, por ejemplo, las etiquetas válidas en un documento, así como los atributos que pueden contener. Estos esquemas XML se definen utilizando XML, por tanto, podríamos definir XML como un metalenguaje.
Por tanto, podemos tener un documento bien formado en XML, pero que no sea válido por no cumplir un esquema definido, pero no podemos tener un documento válido que no esté bien formado. En el Fragmento de Código 1 podemos ver un ejemplo de documento XML válido.
<?xml version="1.0" encoding="UTF-8"?> <Coleccion> <documento> <titulo>El Titulo</titulo> <autor>Miguel S. Mendoza</autor> <fecha>2008</fecha> </documento> <documento> <titulo>El Otro Titulo</titulo> <autor>Catalina S. Román</autor> <fecha>2012</fecha> </documento> </Coleccion>
Cabe señalar que aunque existen similitudes entre XML y HTML, no son exactamente lo mismo. Como hemos señalado anteriormente, XML se trata de un metalenguaje que permite definir estructuras XML que definen documentos, mientras que HTML se trata de un lenguaje propiamente dicho, ya que está definido mediante un DTD o esquema XML. Esto provoca que en HTML podamos encontrar estructuras que, aunque se muestran perfectamente en un navegador, rompen las reglas de documentos bien formados definidas anteriormente. Véanse por ejemplo las etiquetas <br>.
En principio, un documento HTML debe “limpiarse” antes de ser utilizado en una transformación XSLT para asegurarse de que es un documento válido. Por suerte podemos realizar este tipo de tareas de una forma sencilla como veremos más adelante.
Las hojas de estilo escritas en lenguaje XSLT se basan en patrones o reglas que identifican los elementos del documento a transformar y muestran cómo deben presentarse esos elementos en el documento final.
El elemento raíz de una plantilla XSLT es <xsl:stylesheet> o <xsl:transform> que acostumbra a ir acompañado de los atributos xmlns que define el entorno de nombres de etiquetas que se van a utilizar, y el atributo version, que define la versión del esquema en el que vamos a basar las reglas de transformación.
Dentro de una hoja de estilos podemos encontrar otros elementos como:
Dentro de un elemento template se encuentra el contenido de la plantilla que define cómo convertir el contenido de la etiqueta XML del documento original. Para definir esta plantilla se pueden utilizar otros elementos de hoja de estilos que permiten realizar diferentes funciones. Entre esos elementos destacan los siguientes:
Partiendo del documento XML del Fragmento de Código 1, en el Fragmento de Código 2 podemos ver un ejemplo de hoja de estilos XSLT que transformará el documento XML en código HTML.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> <xsl:template match="/"> <html> <body> <h1>Los Documentos</h1> <table> <tr> <th>Titulo</th> <th>Autor</th> </tr> <xsl:for-each select="Coleccion/documento"> <tr> <td><xsl:value-of select="titulo" /></td> <xsl:choose> <xsl:when test="fecha > 2010"> <td style="color: grey"> <xsl:value-of select="autor" /> </td> </xsl:when> <xsl:otherwise> <td style="color: green"> <xsl:value-of select="autor" /> </td> </xsl:otherwise> </xsl:choose> </tr> </xsl:for-each> </table> </body> </html> </xsl:template> </xsl:stylesheet>
Como consecuencia de aplicar la transformación obtendremos el resultado en código HTML que podemos ver en el Fragmento de Código 3.
<html> <body> <h1>Los Documentos</h1> <table> <tr> <th>Titulo</th> <th>Cuerpo</th> </tr> <tr> <td>El Titulo</td> <td style="color: green">Miguel S. Mendoza</td> </tr> <tr> <td>El Otro Titulo</td> <td style="color: grey">Catalina S. Román</td> </tr> </table> </body> </html>
Esto es solo un pequeño ejemplo de las posibilidades que nos brindan las transformaciones en XSLT ya que existen muchos más elementos que se pueden utilizar dentro de una hoja de estilos XSLT para definir transformaciones.
Como hemos podido observar hasta ahora, tanto los documentos como las plantillas son documentos XML. Sin embargo, para poder navegar y encontrar elementos XML concretos dentro de un documento debemos utilizar otro lenguaje que nos permita identificar elementos que cumplan ciertos criterios de forma sencilla. En XSLT, el lenguaje que permite realizar estas acciones se denomina XPath y lo hemos podido ver en ejemplos anteriores en los atributos match, test, y select de los elementos <xsl:template>, <xsl:when> y <xsl:value-of> respectivamente.
En XPath todo objeto XML es tratado como un nodo. A su vez, se distinguen siete tipos de nodos:
Para relacionar nodos, XPath define cinco parentescos entre ellos:
XPath define una sintaxis para definir partes en un documento XML. Utiliza expresiones parecidas a las rutas para navegar entre los elementos y contiene una biblioteca de funciones que se utilizan para distinguir elementos.
Las expresiones más comunes en XPath podrían resumirse en las siguientes:
Con estas expresiones se pueden construir rutas de navegación como las siguientes:
Además de seleccionar nodos en relación a su posición en el documento, podemos seleccionar nodos concretos dependiendo de ciertas características. Para encontrar nodos que contentan ciertos valores o cumplan ciertas propiedades utilizaremos los denominados “predicados”. Los predicados se incluyen en las expresiones XPath entre corchetes. A continuación podemos ver algunos ejemplos:
Se pueden anidar expresiones haciendo uso del operador “|”. Por ejemplo:
Por otro lado, se pueden utilizar comodines en las expresiones XPath, lo que nos permite seleccionar nodos dependiendo de expresiones múltiples. Los comodines más habituales son:
Finalmente, cabe destacar que tanto XSLT como XPath cuentan con una biblioteca de funciones que les permite seleccionar elementos de una forma mucho más eficiente. Podemos encontrar un listado de las mismas en la propia especificación.
En definitiva, XSLT es un lenguaje extremadamente potente que nos permite realizar transformaciones de una forma sencilla y rápida. Aunque la curva de aprendizaje pueda ser un poco complicada, una vez se han realizado unas cuantas transformaciones y se han estudiado correctamente las capacidades de selección de nodos con XPath las posibilidades se abren a cada paso.
En el siguiente artículo se detallan las características que debe poseer un paquete CHPub (Clean HPub) para ser transformado en cualquier sistema de publicación. Basado en la especificación de HPub de Alessandro Morandi para Baker Framework pretende simplificar el mismo y delegar la tarea del diseño y la forma de presentación en el medio de transformación.
<img src="CHPub_A02/img/img01.jpg" alt="Lorem"/>
├── CHPub │ ├── cover.png │ ├── book.json │ ├── CHPub_A1.html │ ├── CHPub_A1 │ │ ├── image │ │ │ ├── cover.png │ │ │ ├── image01.png │ │ ├── video │ │ │ ├── video1.mp4 │ │ │ ├── video2.mp4 │ │ ├── audio │ │ │ ├── audio1.mp3 │ ├── CHPub_A2.html │ ├── CHPub_A2 │ │ ├── image │ │ │ ├── cover.png │ │ │ ├── image01.png │ │ │ ├── image02.png
El fichero book.json se situará en la raíz de la publicación y deberá contener un objeto JSON bien formado. Ejemplo de fichero book.json:
{ "title": "Lorem Ipsum", "author": ["Miguel S. Mendoza", "Marta S. Román"], "creator": ["Gabriel S. Román"], "editor":"NetRunners", "date": "2016-04-29", "url": "http://www.netrunners.es/", "description":"Lorem ipsum dolor sit amet, consectetur adipiscing elit.", "keywords":"specification, hpub, publication", "contents": [ "CHPub_A01", "CHPub_A02", "CHPub_A03", "CHPub_A04" ] }
A diferencia de la especificación original de HPub, en Clean HPub se pretenden crear publicaciones con el menor diseño posible, centradas en el contenido. De esta forma el diseño dependerá exclusivamente del sistema de transformación que reciba la publicación como entrada y genere una publicación en otro formato, ya sea PDF, EPub, etc. La regla es simple: Se permite cualquier etiqueta del estándar HTML4 siempre y cuando no se utilicen el atributo style. Más adelante, en el apartado extensiones, se detallarán etiquetas adicionales relacionadas con los componentes extra que se podrán utilizar.
Para limitar el diseño se especifican a continuación las etiquetas HTML que se permitirán por defecto en lo ficheros HTML de cada apartado para una publicación de libro normal.
Además de las etiquetas HTML básicas descritas anteriormente, y para aumentar la versatilidad de las publicaciones, se han creado etiquetas específicas para diferentes tipos de material. Algunas de ellas están relacionadas con extensiones externas HTML5 que cambiarán dependiendo de la transformación a realizar.
gallery: Esta etiqueta se utilizará para englobar a un conjunto de etiquetas img y mostrarlas como una galería de imágenes.
<gallery> <img src="CHPub_A1/images/imagen01.jpg" alt="Caption 01" /> <img src="CHPub_A1/images/imagen02.jpg" alt="Caption 02" /> <img src="CHPub_A1/images/imagen03.jpg" alt="Caption 03" /> </gallery>
tooltip: Permite mostrar un pequeño tooltip de ayuda sobre un texto concreto. Útil para notas de autor o pequeñas aclaraciones.
<p>Proin <tooltip title="Tooltip Text.">convallis cursus</tooltip> massa.</p>
video: Incluye un vídeo en la publicación. El vídeo podrá ser un fichero en la carpeta del apartado o un identificador de vídeo externo como Vimeo o Youtube. En los siguientes ejemplos los comentarios no son necesarios, solo se añaden para que se identifique el identificador de cada vídeo externo:
<video src="CHPub_A01/video/vide01.mp4">Video description.</video> <-- https://vimeo.com/119787432 --> <video type="vimeo" src="119787432">Video description.</video> <-- https://www.youtube.com/watch?v=bYE67_Wfizw --> <video type="youtube" src="bYE67_Wfizw">Video description.</video>
videogallery: Genera una galería con los vídeos que se introduzcan entre la etiqueta de apertura y cierre:
<videogallery> <source title="Video Title" src="CHPub_A01/video/vide01.mp4">Video description.</source> <source title="Video Title" type="vimeo" src="119787432">Video description.</source> <source title="Video Title" type="youtube" src="bYE67_Wfizw">Video description.</source> <videogallery>
audio: Etiqueta de audio que hará referencia a un fichero en la carpeta del apartado.
<audio src="CHPub_A1/audio/audio01.mp3">Audio Description 01.</audio>
columns: Estructura el contenido en dos o más columnas. Cada columna se representa con la etiqueta column.
<columns> <column> <p>Ut dictum lectus in turpis lacinia, et blandit metus ornare.</p> </column> <column> <p>Nullam at tortor nec nibh interdum laoreet.</p> </column> </columns>
<html> <head> <title>Lorem Ipsum</title> </head> <body> <h1>Neque porro quisquam est qui dolorem</h1> <p>Lorem ipsum dolor sit <strong>amet</strong>, consectetur adipiscing elit.</p> <ul> <li>Proin</li> <li>luctus</li> <li>libero</li> </ul> <img src="CHPub_A1/images/imagen01.jpg" alt="Image Title"> <p>In hac habitasse platea <u>dictumst</u>. Interdum et malesuada fames ac ante ipsum primis in <i>faucibus</i>.</p> <video type="vimeo" src="119787432">Video Decription 01.</video> <h2>Ipsum quia dolor sit amet</h2> <p>Pellentesque hendrerit leo quis mi <a href="http://www.netrunners.es" title="Link Description">lobortis tincidunt</a>. Proin quis felis eget orci <tooltip title="Tooltip Text.">convallis cursus</tooltip> ac eget massa.</p> <ol> <li>odio</li> <li>lectus</li> </ol> <video type="youtube" src="bYE67_Wfizw">Video Decription 02.</video> <h3>Integer orci leo</h3> <blockquote>Donec congue fermentum viverra.</blockquote> <columns> <column> <p>Ut dictum lectus in turpis lacinia, et blandit metus ornare.</p> </column> <column> <p>Nullam at tortor nec nibh interdum laoreet.</p> </column> </columns> <video src="CHPub_A1/video/video01.mp4">Video Decription 03.</video> <h2>Dolor sit amet</h2> <p>Donec sollicitudin diam neque, non lobortis dolor blandit in.</p> <h3>In hac habitasse platea dictumst</h3> <p>Morbi nunc tortor, pellentesque quis augue vel, bibendum venenatis tellus.</p> <audio src="CHPub_A1/audio/audio01.mp3">Audio Description 01.</audio> <p>Mauris eget augue vitae ipsum hendrerit finibus convallis et urna.</p> <gallery> <img src="CHPub_A1/images/imagen02.jpg" alt="Caption 01"> <img src="CHPub_A1/images/imagen03.jpg" alt="Caption 02"> <img src="CHPub_A1/images/imagen04.jpg" alt="Caption 03"> </gallery> </body> </html>