summaryrefslogtreecommitdiff
path: root/index.fr.html
diff options
context:
space:
mode:
authorMiquel Lionel <lionel@les-miquelots.net>2021-05-31 21:06:34 +0100
committerMiquel Lionel <lionel@les-miquelots.net>2021-05-31 21:06:34 +0100
commit805b1c983dd62d53b1be88dc957768e77bb0ba33 (patch)
treed157988aa0e3d42cb4165f5bc8d06f2dd2994e97 /index.fr.html
parente0e590be90f1fba904ee0de997a5cf7f72c5a29c (diff)
downloadxmpp_guide_files-master.tar.gz
xmpp_guide_files-master.zip
add html files for offline readingHEADmaster
Diffstat (limited to 'index.fr.html')
-rwxr-xr-xindex.fr.html932
1 files changed, 932 insertions, 0 deletions
diff --git a/index.fr.html b/index.fr.html
new file mode 100755
index 0000000..f0e62dc
--- /dev/null
+++ b/index.fr.html
@@ -0,0 +1,932 @@
+<!DOCTYPE html>
+<html lang="fr">
+<head>
+<title>Mise en place d'un client web XMPP avec liens de création de compte (conversejs+prosody)</title>
+<link rel='stylesheet' type='text/css' href='styles.css'>
+<meta charset='utf-8'/>
+</head>
+<body>
+<h1>Mise en place d'un client web XMPP avec liens de création de compte (conversejs+prosody)</h1>
+<small>[<a href='partage.les-miquelots.net/blog/2021/index.html#mise-en-place-dun-client-web-xmpp-avec-liens-de-creation-de-compte-conversejsprosody'>lien</a>&mdash;<a href='index.fr.html'>billet seul</a>]</small>
+<p><b>maj 28/05/2021</b>: corrections des iptables (r&eacute;gles dupliqu&eacute;s), ajout de liens de
+documentation, ajout d'une entrée de DNS pour websocket. <samp>http_altconnect</samp> rajouté en module prosody
+pour éviter les erreurs dans la console du navigateur
+<p><b>maj 22/05/2021</b>: OMEMO par pas d&eacute;faut au final, on laisse le choix &agrave;
+l'utilisateur de l'activer dans ses discussions, et c'est mieux niveau historique des messages
+sur plusieurs appareils. On am&eacute;liore aussi la commande apt (-y --no-install-recommends). <br><br>
+<p>Bonjour &agrave; tous, <br><br>
+<p>Aujourd'hui je vais vous montrer comment mettre en place un serveur XMPP avec un
+client Web sur la m&ecirc;me machine, avec la
+possibilit&eacute;
+d'envoyer des liens d'invitations de cr&eacute;ation de comptes ou d'ajout
+en contact pour faciliter l'embarquement de vos proches et amis.
+Je ne fais pas de pr&eacute;sentation du protocole XMPP, c'est hors de la
+port&eacute;e de ce guide et des gens l'explique mieux que moi, je pense
+surtout &agrave; <a
+href="https://www.goffi.org/b/S%C3%A0T_DOTCLEAR_IMPORT_BLOG_default_goffi_99%3A2015%2F06%2F24%2FParlons-XMPP-%C3%A9pisode-1-les-bases">cette
+ suite d'articles de chez goffi.org</a>.<br>
+<b>pav&eacute; c&eacute;sar g&eacute;palu lol</b>: c'est un protocole
+compos&eacute; d'une myriade de standards permettant
+la construction de r&eacute;seaux de messagerie instantan&eacute;e
+d&eacute;centralis&eacute;s et s&eacute;curis&eacute;s. Possibilit&eacute; d'avoir
+des salons publics et priv&eacute;s.
+<br><br>
+
+<p><div id="guide-sommaire">
+ <u>Sommaire:</u>
+ <ol>
+ <li><a href="#xmpp-guide-prereq">Pr&eacute;requis</a></li>
+ <li><a href="#xmpp-guide-dnszone">Configuration zone DNS</a></li>
+ <li><a href="#xmpp-guide-iptables">Configuration pare-feu</a></li>
+ <li><a href="#xmpp-guide-pkgs">Installation des
+ paquets</a></li>
+ <li><a href="#xmpp-guide-certs">Installation des
+ certificats</a></li>
+ <li><a href="#xmpp-guide-confpkgs">Configuration des
+ paquets</a></li>
+ <li><a href="#xmpp-guide-con">Connexion &agrave; l'interface web</a></li>
+ <li><a href="#xmpp-guide-genlinks">G&eacute;n&eacute;ration des liens d'invitation</a></li>
+
+ <li><a href="#xmpp-guide-remarks">Remarques</a></li>
+ <li><a href="#xmpp-guide-docs">Documentations</a></li>
+ <li><a href="#xmpp-guide-thanks">Remerciements</a></li>
+ </ol>
+ </div>
+ <br><br>
+
+<h3 id="xmpp-guide-prereq"><a href="#xmpp-guide-prereq">1.
+Pr&eacute;requis</a></h3>
+
+<p>Tr&ecirc;ve de bavardages, voici ce que l'on va devoir installer:
+<ul>
+ <li><samp>certbot</samp>: g&eacute;n&eacute;ration des certificats
+ pour renforcer la s&eacute;curit&eacute; de la communication
+ client=&gt;serveur et serveur&lt;=&gt;serveur.</li>
+ <li><samp>prosody</samp>: le serveur XMPP, la pi&egrave;ce maîtresse.</li>
+ <li><samp>nginx</samp>: le proxy invers&eacute; qui g&eacute;rera les
+ connexions &agrave; l'interface web et les connexions <span
+ style="color:green"><b>HTTPS</b></span>.</li>
+ <li><samp>conversejs</samp>: l'interface web pour notre serveur XMPP.</li>
+ <li><samp>libjs-bootstrap4 libjs-jquery</samp>: le module
+ <samp><a
+ href="https://modules.prosody.im/mod_invites.html#external-dependencies"
+ target="_blank" rel="noopener" >mod_invites</a></samp> de Prosody a
+ besoin de ces biblioth&egrave;ques pour le CSS et bouts de JavaScript.
+ <li><samp>hg</samp>: pour cloner le d&eacute;pôt des modules de
+ <samp>prosody</samp> et les maintenir &agrave; jour.</li>
+</ul><br>
+
+
+<p>Mettez-vous d'accord sur votre nom de domaine: vous remplacerez les
+occurences de <samp>exemple.fr</samp> dans ce guide par votre
+nom de domaine. On va aussi utiliser un sous-domaine pour
+l'interface web, <samp>chat.exemple.fr</samp>, un qui contiendra les
+salons publics et priv&eacute;s, <samp>salons.exemple.fr</samp> et un
+autre pour le serveur d'envoi de fichiers,
+<samp>f.exemple.fr</samp>.<br>
+N'oubliez pas de rajouter des entr&eacute;es DNS type A pour ces
+sous-domaines.
+<br><br>
+
+<h3 id="xmpp-guide-dnszone"><a href="#xmpp-guide-dnszone">2. Configuration zone DNS</a></h3>
+<p>Tout d'abord, rendez-vous dans la zone DNS de votre nom de domaine, on va
+rajouter quelques entr&eacute;es de type SRV et TXT pour faciliter la
+communication des clients et serveurs XMPP avec nous (plus de
+d&eacute;tails en anglais <a
+href="https://wiki.xmpp.org/web/SRV_Records">par l&agrave;</a> ou <a
+href="https://prosody.im/doc/dns">encore ici</a>):
+<pre>
+_xmpp-client._tcp.exemple.fr 86400 SRV 1 1 5222 exemple.fr.
+_xmpps-client._tcp.exemple.fr 86400 SRV 1 1 5223 exemple.fr.
+_xmpp-server._tcp.exemple.fr 86400 SRV 1 1 5269 exemple.fr.
+_xmppconnect.exemple.fr TXT _xmpp-client-xbosh=https://chat.exemple.fr/http-bind
+_xmppconnect.exemple.fr TXT _xmpp-client-websocket=wss://chat.example.fr/xmpp-websocket
+</pre>
+
+<p><b>À noter:</b> le <samp>exemple.fr</samp> &agrave; de gauche
+repr&eacute;nte le domaine XMPP, celui de droite est le serveur qui
+r&eacute;pondra aux requ&ecirc;tes et une entr&eacute;e DNS de type A
+doit exister pour celui-ci, pas de raccourci type CNAME autoris&eacute;.
+C'est pratique quand vous voulez des adresses utilisateurs "propres" tel
+que <u>vous@exemple.fr</u> mais que le serveur est en fait sur le
+sous-domaine <samp>xmpp.exemple.fr</samp>. Si c'est le cas, changez
+alors le <samp>exemple.fr</samp> de droite par
+<samp>xmpp.exemple.fr</samp>.<br><br>
+
+
+<h3 id="xmpp-guide-iptables"><a href="#xmpp-guide-iptables">3. Configuration pare-feu</a></h3>
+<p><b><u>IMPORTANT</u>:Connectez-vous en tant que root avant d'ex&eacute;cutez les
+commandes contenues dans
+ce tutoriel</b>. On va ensuite configurer des r&egrave;gles
+<samp>iptables</samp> pour &eacute;viter de se mordre les doigts
+de rage par la suite. Je pars du principe que vous avez d&eacute;j&agrave;
+ configur&eacute; quelques r&egrave;gles vous permettant de SSH tranquillou.
+
+<pre>
+iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 5222 -j ACCEPT # on accepte les connexions client &agrave; serveur
+iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 5223 -j ACCEPT # pareil que le dessus mais celles qui sont chiffr&eacute;s.
+iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 5269 -j ACCEPT # connexions serveur &agrave; serveur.
+iptables -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT # HTTP pour l'interface web
+iptables -A INPUT -p tcp -m tcp --dport 443 -j ACCEPT # HTTPS
+iptables -A OUTPUT -p udp -m udp --dport 53 -j ACCEPT # pour envoyer des requ&ecirc;te DNS
+iptables -A OUTPUT -p tcp -m tcp --dport 80 -j ACCEPT # en output aussi si des serveurs utilisant l'HTTP upload pour les pjs
+iptables -A OUTPUT -p tcp -m tcp --dport 443 -j ACCEPT
+
+iptables-save &gt; /etc/iptables/iptables.rules
+
+
+# pareil pour l'ipv6
+ip6tables -A INPUT -p tcp -m state --state NEW -m tcp --dport 5222 -j ACCEPT
+ip6tables -A INPUT -p tcp -m state --state NEW -m tcp --dport 5223 -j ACCEPT
+ip6tables -A INPUT -p tcp -m state --state NEW -m tcp --dport 5269 -j ACCEPT
+ip6tables -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT # HTTP pour l'interface web
+ip6tables -A INPUT -p tcp -m tcp --dport 443 -j ACCEPT # HTTPS
+ip6tables -A OUTPUT -p udp -m udp --dport 53 -j ACCEPT # pour envoyer des requ&ecirc;te DNS
+ip6tables -A OUTPUT -p tcp -m tcp --dport 80 -j ACCEPT # en output aussi si des serveurs utilise l'HTTP upload pour les pjs
+ip6tables -A OUTPUT -p tcp -m tcp --dport 443 -j ACCEPT
+
+ip6tables-save &gt; /etc/iptables/ip6tables.rules
+systemctl enable --now iptables # activation du service iptables si pas
+# d&eacute;j&agrave; fait pour garder la config du pare-feu apr&egrave;s reboot.
+</pre><br>
+
+<h3 id="xmpp-guide-pkgs"><a href="#xmpp-guide-pkgs">4. Installation des paquets</a></h3>
+
+<p>Apr&egrave;s ceci, installez <samp>prosody</samp> depuis <a
+href="https://prosody.im/doc/installing_from_source">les sources</a> ou
+votre <a href="https://prosody.im/download/start">installeur de
+paquets</a>. On en profitera pour installer les autres composants requis
+&agrave; ce guide. Sur un Debian classique cel&agrave; donnera:<br>
+<pre>sudo apt-get install -y --no-install-recommends prosody nginx-full \
+certbot python3-certbot-nginx \
+mercurial libjs-bootstrap4 libjs-jquery</pre><br>
+
+<p>On va maintenant cloner les <samp>prosody-modules</samp> depuis la
+source. Il n'est pas toujours &agrave; jour dans les d&eacute;p&ocirc;ts de
+paquets:
+<pre>
+hg clone https://hg.prosody.im/prosody-modules/ /usr/lib/prosody/modules/
+</pre>
+<p>On pr&eacute;pare en m&ecirc;me temps un script pour mettre
+&agrave; automatiquement via la crontab. Cr&eacute;ez le fichier
+<samp>/usr/local/sbin/maj_prosodymods.sh</samp> avec le contenu suivant:
+<pre>
+#!/bin/sh
+MODDIR="/usr/lib/prosody/modules/"
+
+if test -d $MODDIR; then
+ cd $MODDIR
+ hg pull --update
+else
+ mkdir -p /usr/lib/prosody
+ hg clone https://hg.prosody.im/prosody-modules/ $MODDIR
+fi
+</pre>
+<p>N'oubliez pas de faire un coup de <samp>chmod +x</samp> dessus...
+<br><br>
+
+<p>On va ensuite t&eacute;l&eacute;charger <samp>conversejs</samp>.
+&Agrave; ce jour sur Debian Buster, il n'y a pas de paquet &agrave; jour
+officiel pour <samp>conversejs</samp>, donc on va faire un script qu'on
+int&eacute;grera dans notre crontab.<br>
+Ins&eacute;rez le contenu suivant
+dans le fichier <samp>/usr/local/sbin/update_conversejs.sh</samp> puis
+rendez-le ex&eacute;cutable:
+<pre>
+#!/bin/sh
+TEMPDIR="$(mktemp -d)"
+LOG=/var/log/update_conversejs.log
+WWWDIR='/var/www/chat.exemple.fr'
+WWWUSER='www-data' # cette valeur sera s&ucirc;rement diff&eacute;rente
+ # si vous n'&ecirc;tes pas sur Debian avec nginx.
+ # par ex. &ccedil;a sera 'http' sous Arch avec nginx.
+
+mkdir -p $WWWDIR/dist
+cd $TEMPDIR
+printf "\n\n$(date) - INFO - Starting updating conversejs..." | tee -a $LOG
+CURL_ERR=$(curl -s \
+ https://api.github.com/repos/conversejs/converse.js/releases/latest | \
+ grep -o "https://.*\.tgz" | \
+ grep converse\.js- | \
+ xargs curl -fsOJL) || \
+ (printf "\n$(date) - ERR - Updating conversejs failed." | tee -a $LOG &amp;&amp; exit)
+
+# on installe libsignal pour pouvoir utiliser OMEMO
+# dans le client web
+if test -e "$WWWDIR/dist/libsignal-protocol.min.js"; then
+ printf "\n$(date) - TOK - Libsignal already installed, skipping." | tee -a $LOG
+else
+ curl -fsOJL \
+ https://cdn.conversejs.org/3rdparty/libsignal-protocol.min.js || \
+ (printf "\n$(date) - ERR - Updating libsignal-protocol-javascript failed." | \
+ tee -a $LOG)
+ cp libsignal*.js $WWWDIR/dist/
+fi
+
+tar xzf *.tgz
+cp -rf package/dist $WWWDIR/
+sed "s/fullscreen\.html/index\.html/g" package/manifest.json &gt; $WWWDIR/manifest.json
+chown $WWWUSER:$WWWUSER -R $WWWDIR/
+chmod 755 -R $WWWDIR/
+rm -rf $TEMPDIR
+printf "\n$(date) - TOK - Done." | tee -a $LOG
+</pre>
+<p>Ex&eacute;cutez ce fichier pour gagner du temps dans l'<a
+href="#xmpp-guide-confpkgs">&eacute;tape 6</a>, vous n'aurez pas &agrave;
+cr&eacute;er le <samp>$WWWDIR</samp>.
+
+<h3 id="xmpp-guide-certs"><a href="#xmpp-guide-certs">5. Installation des
+certificats</a></h3>
+
+
+<p>On va ensuite lancer certbot pour g&eacute;n&eacute;rer des certificats.
+Je pars du principe que vous avez configur&eacute; les entr&eacute;es de
+type A pour <samp>exemple.fr</samp>, <samp>chat.exemple.fr</samp>
+et <samp>f.exemple.fr</samp> dans votre zone DNS:
+<pre>certbot certonly --agree-tos --nginx --deploy-hook "prosodyctl --root cert import /etc/letsencrypt/live" -d chat.exemple.fr -d exemple.fr -d f.exemple.fr -d salons.exemple.fr </pre>
+<p>Une fois que cette commande s'ex&eacute;cute avec succ&eacute;s, des
+dossiers correspondants aux domaines demand&eacute;s devrait
+appara&icirc;tre dans <samp>/etc/letsencrypt/live/</samp>.
+<br><br>
+
+<h3 id="xmpp-guide-confpkgs"><a href="#xmpp-guide-confpkgs">6. Configuration des
+paquets</a></h3>
+
+<p>Le moment est venu! On va t&acirc;ter &acirc; prosody et sa
+configuration.<br>
+Ouvrez le fichier <samp>/usr/lib/prosody/net/http/server.lua</samp>, on va simplifier la
+connexion entre l'interface HTTP de prosody (BOSH) et nginx.<br>
+Dans le
+fichier, trouver la ligne suivante:
+<pre>
+headers = { date = date_header, connection = response_conn_header };
+</pre>
+<p>et rempla&ccedil;ez la par:
+<pre>
+headers = { date = date_header, connection = response_conn_header,
+ access_control_allow_origin = "exemple.fr" };
+-- si 'exemple.fr' ne r&eacute;sout pas le soucis de connexion, mettez
+-- un '*' &agrave; la place. Pour rappel, c'est l'adresse du serveur XMPP
+-- qui faut mettre, et non celle du domaine.
+</pre><br>
+
+<p>Ensuite, on va s'occuper du script qui permettra d'envoyer des fichiers
+&agrave; d'autres utilisateurs. Ex&eacute;cutez ceci:
+<pre>
+mkdir -p /var/www/upload
+chown www-data:www-data /var/www/upload # l'utilisateur de nginx peut
+ # diff&eacute;rer selon la distrib, faites gaffe
+mkdir -p /usr/local/lib/perl
+wget -O /usr/local/lib/perl/upload.pm https://raw.githubusercontent.com/weiss/ngx_http_upload/master/upload.pm
+</pre>
+<p>Ouvrez le fichier <samp>upload.pm</samp>, cherchez un bout de texte
+ressemblant &agrave; <samp>my $external_secret = 'it-is-secret';</samp>
+et changez le <samp>it-is-secret</samp> par un mot de passe fort, de
+pr&eacute;f&egrave;rence sans apostrophe ou antislash pour &eacute;viter
+que le programme en Perl plantouille quand on va tout d&eacute;marrer.<br>
+Notez-vous ce mot de passe sur un bout de papier, on va en avoir besoin
+derechef.<br><br>
+
+<p>Passons &agrave; la configuration de prosody: &eacute;ditez le fichier
+ <samp>/etc/prosody/prosody.cfg.lua</samp> avec les informations
+suivantes:
+<pre>
+admins = { "vous@exemple.fr" }
+
+-- For more information see: https://prosody.im/doc/libevent
+-- use_libevent = true
+
+plugin_paths = { "/usr/lib/prosody/modules" }
+
+modules_enabled = {
+
+ -- Generally required
+ "roster"; -- Allow users to have a roster. Recommended ;)
+ "saslauth"; -- Authentication for clients and servers. Recommended if you want to log in.
+ "tls"; -- Add support for secure TLS on c2s/s2s connections
+ "dialback"; -- s2s dialback support
+ "disco"; -- Service discovery
+
+ -- Not essential, but recommended
+ "carbons"; -- Keep multiple clients in sync
+ "carbons_copies";
+ "carbons_copies_adhoc";
+ "pep"; -- Enables users to publish their avatar, mood, activity, playing music and more
+ "private"; -- Private XML storage (for room bookmarks, etc.)
+ "blocklist"; -- Allow users to block communications with other users
+ "vcard4"; -- User profiles (stored in PEP)
+ "vcard_legacy"; -- Conversion between legacy vCard and PEP Avatar, vcard
+ "smacks";
+ "bookmarks"; -- vieux module mais compatible avec la
+ -- majorit&eacute; des clients XMPP contrairement
+ -- &agrave; bookmarks2
+ --"bookmarks2";
+ "presence"; -- voir l'&eacute;tat de l'utilisateur (en ligne, hors
+ -- ligne, etc...)
+ "offline";
+
+ -- Nice to have
+ "version"; -- Replies to server version requests
+ "uptime"; -- Report how long server has been running
+ "time"; -- Let others know the time here on this server
+ "ping"; -- Replies to XMPP pings with pongs
+ "register"; -- Allow users to register on this server using a client and change passwords
+ "mam"; -- Store messages in an archive and allow users to access it
+ "csi";
+ "csi_simple"; -- Simple Mobile optimizations
+ "csi_battery_saver";
+ "vjud"; -- recherche d'utilisateurs dans les salons
+
+ -- Admin interfaces
+ "admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands
+
+ -- HTTP modules
+ "bosh"; -- Enable BOSH clients, aka "Jabber over HTTP"
+ "websocket"; -- XMPP over WebSockets
+ "http_altconnect";
+
+ -- Other specific functionality
+ "posix"; -- POSIX functionality, sends server to background, enables syslog, etc.
+ "limits"; -- Enable bandwidth limiting for XMPP connections
+ "groups"; -- Shared roster support
+ "server_contact_info"; -- Publish contact information for this service
+ "announce"; -- Send announcement to all online users
+ "welcome"; -- Welcome users who register accounts
+ "watchregistrations"; -- Alert admins of registrations
+ "motd"; -- Send a message to users when they log in
+ --"legacyauth"; -- Legacy authentication. Only used by some old clients and bots.
+ --"proxy65"; -- Enables a file transfer proxy service which clients behind NAT can use
+}
+
+-- These modules are auto-loaded, but should you want
+-- to disable them then uncomment them here:
+modules_disabled = {
+ -- "offline"; -- Store offline messages
+ -- "c2s"; -- Handle client connections
+ -- "s2s"; -- Handle server-to-server connections
+}
+
+motd_text = [[Bonjour &agrave; tous ! Bienvenue sur mon serveur XMPP. Clavardez heureux !]]
+welcome_message = "C'est ta premi&egrave;re connexion, $username. Bienvenue &agrave; toi."
+
+daemonize = false;
+pidfile = "/run/prosody/prosody.pid";
+trusted_proxies = { "127.0.0.1", "::1" }
+
+-- Force certificate authentication for server-to-server connections
+c2s_require_encryption = true -- chiffrement requis pour connexion client &agrave; serveur
+s2s_require_encryption = true -- chiffrement requis pour connexion entre serveurs
+s2s_secure_auth = true
+authentication = "internal_hashed"
+
+-- mam settings
+archive_expires_after = "never" -- historique permanent des chats
+
+log = {
+ -- Log files (change 'info' to 'debug' for debug logs):
+ info = "/var/log/prosody/prosody.log";
+ error = "/var/log/prosody/prosody.err";
+ -- Syslog:
+ { levels = { "error" }; to = "syslog"; };
+}
+
+-- http and certificate shenanigans
+certificates = "certs"
+
+-- Include "conf.d/*.cfg.lua"
+
+legacy_ssl_ports = { 5223 }
+-- http_ports = { 5280 }
+-- http_interface = { "*" }
+-- https_ports = { 5281 }
+-- https_interfaces { "*" }
+
+
+cross_domain_bosh = { "https://chat.exemple.fr" }
+cross_domain_websocket = { "https://chat.exemple.fr" }
+consider_bosh_secure = true
+consider_websocket_secure = true
+allow_registration = true -- n&eacute;cessaire pour mod_invites
+registration_invite_only = true -- inscription autoris&eacute; seulement avec les invitations
+vjud_mode = "opt-in" -- l'utilisateur doit consentir pour que la recherche vjud
+ -- le fasse remonter dans les r&eacute;sultats.
+
+-- https://prosody.im/security/advisory_20210512/
+gc = {
+ speed = 500;
+}
+c2s_stanza_size_limit = 256 * 1024
+s2s_stanza_size_limit = 512 * 1024
+
+limits = {
+ c2s = {
+ rate = "10kb/s";
+ };
+ s2sin = {
+ rate = "3kb/s";
+ };
+}
+-- https://prosody.im/security/advisory_20210512/
+
+ssl = {
+ key = "certs/exemple.fr.key";
+ certificate = "certs/exemple.fr.crt";
+}
+
+VirtualHost "exemple.fr"
+ invites_page = "https://chat.exemple.fr/invite?{invite.token}"
+ webchat_url = "https://chat.exemple.fr/"
+ http_external_url = "https://chat.exemple.fr/"
+ invite_expiry = 86400 * 7 -- 7 jours avant qu'un lien d'invitation expire
+ http_paths = {
+ invites_page = "/invite";
+ invites_register_web = "/register";
+ }
+
+ modules_enabled = {
+ "invites";
+ "invites_adhoc";
+ "invites_page";
+ "invites_register";
+ "invites_register_web";
+ "http_libjs";
+ }
+
+ contact_info = {
+ abuse = { "mailto:vous@exemple.fr", "xmpp:vous@exemple.fr" };
+ admin = { "mailto:vous@exemple.fr", "xmpp:vous@exemple.fr" };
+ security = { "mailto:vous@exemple.fr", "xmpp:vous@exemple.fr" };
+ support = { "mailto:vous@exemple.fr", "xmpp:vous@exemple.fr" };
+ };
+
+ https_certificate = "certs/exemple.fr.crt";
+ ssl = {
+ key = "certs/exemple.fr.key";
+ certificate = "certs/exemple.fr.crt";
+ }
+
+ Component "f.exemple.fr" "http_upload_external"
+ http_upload_external_base_url = "https://f.exemple.fr/"
+ http_upload_external_secret = "its-a-secret"
+ http_upload_external_file_size_limit = 104857600 -- limite de &agrave; 100Mo pour les envois de pjs
+ ssl = {
+ key = "certs/f.exemple.fr.key";
+ certificate = "certs/f.exemple.fr.crt";
+ }
+
+ Component "salons.exemple.fr" "muc"
+ name = "Salons (chatrooms) chez exemple.fr"
+ modules_enabled = { "muc_mam", "vcard_muc" }
+ muc_room_default_language = "fr"
+ muc_log_expires_after = "never" -- histo permanent des groupes de
+ -- chats
+ log_all_rooms = true
+ muc_log_by_default = true
+ muc_log_presences = false
+ restrict_room_creation = "admin" -- seul l'admin peut cr&eacute;er des salons
+ ssl = {
+ key = "certs/salons.exemple.fr.key";
+ certificate = "certs/salons.exemple.fr.crt";
+ }
+</pre>
+<p>Oui, il faut rempla&ccedil;er <u><samp>its-a-secret</samp></u> par le
+mot de passe que vous avez not&eacute; tout &agrave; l'heure.<br>
+Certains auront aussi remarqu&eacute; qu'on a d&eacute;fini un utilisateur
+administrateur au d&eacute;but du fichier de config,
+<u>vous@exemple.fr</u>. On va donc cr&eacute;er l'utilisateur avec la
+commande:
+<pre>
+prosodyctl check # &ccedil;a va v&eacute;rifier si y'a des soucis dans la configuration
+prosodyctl adduser vous@exemple.fr
+</pre><br>
+
+<p>Cr&eacute;ez le fichier
+<samp>/var/www/chat.exemple.fr/index.html</samp> avec le texte suivant:
+<pre>
+&lt;!DOCTYPE html&gt;
+&lt;html class="no-js" lang="en"&gt;
+ &lt;head&gt;
+ &lt;title&gt;Converse&lt;/title&gt;
+ &lt;meta charset="utf-8"/&gt;
+ &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"/&gt;
+ &lt;meta name="description" content="Converse XMPP/Jabber Chat"/&gt;
+ &lt;meta name="keywords" content="xmpp chat webchat converse.js" /&gt;
+ &lt;link rel="manifest" href="/manifest.json"&gt;
+ &lt;link type="text/css" rel="stylesheet" media="screen" href="/dist/converse.min.css" /&gt;
+ &lt;script src="/dist/libsignal-protocol.min.js"&gt;&lt;/script&gt;
+ &lt;script src="/dist/converse.min.js"&gt;&lt;/script&gt;
+ &lt;/head&gt;
+ &lt;body class="converse-fullscreen"&gt;
+ &lt;noscript&gt;You need to enable JavaScript to run the Converse.js chat app.&lt;/noscript&gt;
+ &lt;div id="conversejs-bg"&gt;&lt;/div&gt;
+ &lt;script&gt;
+ /*
+ @licstart
+ This is free and unencumbered software released into the public domain.
+
+ Anyone is free to copy, modify, publish, use, compile, sell, or
+ distribute this software, either in source code form or as a compiled
+ binary, for any purpose, commercial or non-commercial, and by any
+ means.
+
+ In jurisdictions that recognize copyright laws, the author or authors
+ of this software dedicate any and all copyright interest in the
+ software to the public domain. We make this dedication for the benefit
+ of the public at large and to the detriment of our heirs and
+ successors. We intend this dedication to be an overt act of
+ relinquishment in perpetuity of all present and future rights to this
+ software under copyright law.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+
+ For more information, please refer to &lt;http://unlicense.org/&gt;
+ @licend
+ */
+ converse.initialize({
+ auto_away: 300, //absent au bout de 5minutes
+ auto_list_rooms: true,
+ auto_reconnect: true,
+ auto_xa: 600, //absence prolong&eacute;e au bout de 10minutes
+ bosh_service_url: 'https://chat.exemple.fr/http-bind/',
+ csi_waiting_time: 60,
+ enable_smacks: true,
+ i18n: 'fr', // pour avoir l'interface en fran&ccedil;ais
+ locked_domain: exemple.fr, // on verouille le domaine autoris&eacute;&agrave; se connecter
+ message_archiving: 'always',
+ persistent_store: 'IndexedDB', // jcbrand a dit qu'en 8.0.0
+ play_sounds: true,
+ // ça va aller plus vite avec l'IndexedDB
+ theme: 'concord',
+ view_mode: 'fullscreen',
+ websocket_url: 'wss://chat.exemple.fr/xmpp-websocket',
+ });
+ &lt;/script&gt;
+ &lt;/body&gt;
+&lt;/html&gt;
+</pre><br>
+
+<p>C'est presque la fin de ce guide ! On va maintenant cr&eacute;er les
+fichiers de configuration nginx. <br>
+Cr&eacute;ons <samp>/etc/nginx/sites-enabled/exemple.fr.conf</samp> pour
+commencer:
+<pre>
+server {
+ listen 80;
+ server_name exemple.fr;
+
+ location / {
+ return 301 https://$host$uri;
+ }
+}
+
+server {
+ listen 443 ssl;
+ server_nam exemple.fr;
+ ssl_certificate /etc/letsencrypt/live/exemple.fr/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/exemple.fr/privkey.pem;
+
+ # this block is for the prosody's http_altconnect module
+ location ~* host-(meta|meta\.json) {
+ proxy_pass http://example.com:5280$uri;
+ proxy_http_version 1.1;
+ }
+}
+</pre><br>
+
+<p>Ensuite, cr&eacute;ez
+<samp>/etc/nginx/sites-enabled/f.exemple.fr.conf</samp>, ce sera pour le
+composant
+qui g&eacute;rera les pi&egrave;ces jointes:
+<pre>
+perl_modules /usr/local/lib/perl; # Path to upload.pm.
+perl_require upload.pm;
+
+server {
+ listen 80;
+ server_name f.exemple.fr;
+ location / {
+ return 301 https://$host$request_uri;
+ }
+}
+
+server {
+ # Specify directives such as "listen", "server_name", and TLS-related
+ # settings for the "server" that handles the uploads.
+ listen 443 ssl http2;
+ server_name f.exemple.fr;
+
+ ssl_certificate /etc/letsencrypt/live/f.exemple.fr/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/f.exemple.fr/privkey.pem;
+ # Uploaded files will be stored below the "root" directory. To minimize
+ # disk I/O, make sure the specified path is on the same file system as
+ # the directory used by Nginx to store temporary files holding request
+ # bodies ("client_body_temp_path", often some directory below /var).
+ root /var/www/upload;
+ index index.html;
+ # Specify this "location" block (if you don't use "/", see below):
+ location / {
+ perl upload::handle;
+ }
+
+ # Upload file size limit (default: 1m), also specified in your XMPP
+ # server's upload module configuration (see below):
+ client_max_body_size 100m;
+}
+</pre>
+<p>Ex&eacute;cutez <samp>nginx -t</samp> pour tester la configuration. Si
+aucune erreur n'est d&eacute;tect&eacute;e, cr&eacute;er le fichier
+<samp>/etc/nginx/sites-enabled/chat.exemple.fr.conf</samp>:
+<pre>
+server {
+ listen 80;
+ server_name chat.exemple.fr;
+
+ location / {
+ return 301 https://$host$uri;
+ }
+}
+
+server {
+ listen 443 ssl http2;
+ ssl_certificate /etc/letsencrypt/live/chat.exemple.fr/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/chat.exemple.fr/privkey.pem;
+ root /var/www/chat.exemple.fr;
+ index index.html;
+
+ # XMPP BOSH
+ location ^~ /http-bind {
+ proxy_pass https://exemple.fr:5281/http-bind;
+ proxy_http_version 1.1;
+ proxy_set_header Host exemple.fr;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_buffering off;
+ tcp_nodelay on;
+ }
+
+ # XMPP HTTP-Upload
+ location ^~ /upload {
+ proxy_pass https://f.exemple.fr; proxy_http_version 1.1;
+ proxy_set_header Host exemple.fr;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_set_header X-Forwarded-For $remote_addr;
+ proxy_buffering off;
+ tcp_nodelay on;
+ }
+
+ # XMPP Websockets
+ location /xmpp-websocket {
+ proxy_pass http://exemple.fr:5280/xmpp-websocket;
+ proxy_http_version 1.1;
+ proxy_buffering off;
+ proxy_set_header Connection "Upgrade";
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Host $host;
+ proxy_set_header X-Forwarded-For $remote_addr;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_read_timeout 900s;
+ }
+
+ # XMPP Account invite
+ location ^~ /invite {
+ proxy_pass https://exemple.fr:5281/invite;
+ proxy_http_version 1.1;
+ proxy_set_header Host exemple.fr;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_set_header X-Forwarded-For $remote_addr;
+ proxy_buffering off;
+ tcp_nodelay on;
+ }
+
+ # XMPP account register
+ location ^~ /register {
+ proxy_pass https://exemple.fr:5281/register;
+ proxy_http_version 1.1;
+ proxy_set_header Host exemple.fr;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_set_header X-Forwarded-For $remote_addr;
+ proxy_buffering off;
+ tcp_nodelay on;
+ }
+
+ # sur mon vps debian j'ai eu besoin de &ccedil;a pour
+ # que les pages d'invitation soit bien
+ # format&eacute;es
+ location = /share/bootstrap4/css/bootstrap.min.css {
+ alias /usr/lib/nodejs/bootstrap/dist/css/bootstrap.min.css;
+ }
+
+ location = /share/jquery/jquery.min.js {
+ alias /usr/lib/nodejs/jquery/dist/jquery.min.js;
+ }
+
+ location = /share/bootstrap4/js/bootstrap.min.js {
+ alias /usr/lib/nodejs/bootstrap/dist/js/bootstrap.min.js;
+ }
+
+}
+</pre>
+<p>Ex&eacute;cutez de nouveau <samp>nginx -t</samp> pour d&eacute;tecter
+d'&eacute;ventuels probl&egrave;mes de configuration. Une fois que tout
+est OK, ajoutez la ligne <samp>127.0.0.1 exemple.fr</samp>
+dans le fichier <samp>/etc/hosts</samp>.<br>
+Red&eacute;marrez le serveur Prosody et Nginx:
+<pre>
+systemctl start prosody nginx
+# ou
+prosodyctl start &amp;&amp; nginx -s reload
+</pre><br>
+
+<h3 id="xmpp-guide-con"><a
+href="#xmpp-guide-con">7. Connexion &agrave; l'interface web:</a></h3>
+<p>Rendez-vous maintenant sur la page web du chat: pour notre
+guide &ccedil;a serait <a
+href="https://chat.exemple.fr">https://chat.exemple.fr</a>
+, adaptez avec ce que vous avez.<br>
+Vous devriez voir quelque chose comme &ccedil;a:<br>
+<a href="img/conversejs_login.png"><img
+src="img/conversejs_login.png"></a>
+
+<p><b>Petite astuce</b>: si vous voulez vous connecter avec l'utilisateur
+<u><samp>vous@exemple.fr</samp></u> vous pouvez omettre la partie droite
+de votre adresse, comme ceci:<br>
+<a href="img/conversejs_logintrick.png"><img
+src="img/conversejs_logintrick.png"></a>
+
+<p>C'est gr&acirc;ce &agrave; la configuration de
+<samp><a
+href="https://conversejs.org/docs/html/configuration.html?highlight=locked_domain#locked-domain"
+target="_blank" rel="noopener">locked_domain</a></samp> lors de l'initialisation de Converse.js.<br>
+Une fois connect&eacute;, l'interface ressemblera a ceci:<br>
+<a href="img/conversejs_main.png"><img
+src="img/conversejs_main.png"></a>
+
+<p>Vous pouvez alors commencer &agrave; utiliser XMPP et rejoindre ou
+cr&eacute;er des salons, ajouter des contacts et bien s&ucirc;r discuter depuis
+cette interface web !<br><br>
+
+<h3 id="xmpp-guide-genlinks"><a href="#xmpp-guide-genlinks">8.
+G&eacute;n&eacute;ration des liens d'invitation</a></h3>
+
+<p>La chose qui nous int&eacute;resse surtout c'est la cr&eacute;ation
+de liens d'invitation accessible depuis le Web.<br>
+Pour ce faire, cliquez gauche sur la roue dent&eacute;e en haut &agrave; gauche
+&agrave; c&ocirc;t&eacute; de votre nom, cliquez sur <u>Commandes</u>.
+Dans le champ <u>"Sur quelle entit&eacute; voulez-vous lancer des
+commandes ?"</u> rentrez le nom de votre serveur XMPP, puis cliquez sur
+<u>"Lister les commandes disponibles"</u>. Vous devez avoir quelque chose
+de similaire &agrave; ceci:<br>
+<a href="img/conversejs_adhoc1.png"><img
+src="img/conversejs_adhoc1.png"></a><br>
+
+<p>Descendez un peu jusqu'&agrave; voir <u>"Create new contact invite"</u>
+et cliquez dessus:<br>
+<a href="img/conversejs_adhoc2.png"><img
+src="img/conversejs_adhoc2.png"></a><br>
+Une invitation s'est cr&eacute;&eacute;e ! Vous pouvez alors copier le texte
+contenu dans <u>"Invite web page"</u> et l'envoyer &agrave; l'un de vos amis,
+proches, etc...<br>
+Une fois ouvert, le lien am&egrave;ne sur une page de ce type:<br>
+<a href="img/conversejs_invitepage.png"><img
+src="img/conversejs_invitepage.png"></a><br>
+<p>La page d&eacute;tecte automatiquement votre plateforme et vous propose
+des applications XMPP natives en fonction. Dans le cas ou la plateforme
+est un smartphone, &ccedil;a am&eacute;nera sur la page de
+t&eacute;l&eacute;chargement de l'application puis ouvrira celle-ci tout
+en continuant l'inscription.<br>
+Le lien entour&eacute; de rouge
+en bas avec le texte <u>"register an account manually"</u> permet de
+s'inscrire via un formulaire web. Pratique pour juste cr&eacute;er le
+compte et le tester plus tard. Voici &agrave; quoi &ccedil;a
+ressemble:<br>
+<a href="img/conversejs_register1.png"><img
+src="img/conversejs_register1.png"></a><br>
+<p>Vous pouvez voir que j'ai commenc&eacute; a remplir le formulaire: une
+fois l'inscription envoy&eacute;e en cliquant sur le bouton
+<u>"Submit"</u>, vous serez accueilli par l'&eacute;cran
+suivant:<br>
+<a href="img/conversejs_register2.png"><img
+src="img/conversejs_register2.png"></a><br>
+<p>Une page vous confirmant votre inscription s'affiche, avec la
+possibilit&eacute; de montrer de nouveau le mot de passe saisie lors de
+l'inscription ou cas o&ugrave; (le bouton <u>"Show"</u>).<br>
+Le bouton ento&ucirc;r&eacute; de rouge, <u>"Log in via web"</u>,
+permettra
+&agrave; l'utilisateur inscrit de se connecter &agrave; l'interface web
+configur&eacute;e pendant ce tutoriel, et il vous aura en tant que
+contact.<br>
+<a href="img/conversejs_chatting.png"><img
+src="img/conversejs_chatting.png"></a><br>
+
+<h3 id="xmpp-guide-remarks"><a href="#xmpp-guide-remarks">9. Remarques</a></h3>
+<p>Le guide se finit ici! Je reviendrais pour corriger quelques fautes,
+&eacute;tourderies et oublis si j'en aper&ccedil;ois.
+J'ai des remarques &agrave; faire sur le logiciel:
+<ul style="list-style:disclosure-closed">
+ <li>Les messages chiffr&eacute;s OMEMO ne semblent pas lisibles entres
+ clients Converse.js. L'envoyeur peut lire son message OMEMO, mais si
+ le destinataire utilise uniquement converse.js, il y a de fortes
+ chances qu'il voit un message du type <u>"Ceci est un message chiffr&eacute;
+ avec OMEMO, que votre client ne semble pas prendre en charge..."</u>.
+ Des clients tel que Gajim ou Dino n'ont pas de soucis de ce
+ c&ocirc;t&eacute; l&agrave; d'apr&eacute;s mon exp&eacute;rience. J'ai
+ peut-&ecirc;tre aussi une erreur de configuration...</li>
+ <li>Je vous conseille d'utilisateur un seul navigateur pour
+ Converse.js si vous aimez avoir un historique des messages consistant.</li>
+ <li>Le chiffrement des pi&egrave;ces jointes n'est pas encore
+ impl&eacute;ment&eacute; (source: @jcbrand dans le salon
+ discuss@conference.conversejs.org).</li>
+ <li>Si vous voulez traduire en fran&ccedil;ais les pages
+ d'inscriptions, je vous invite &agrave; regarder le code source des
+ modules <samp>mod_invites_pages</samp>, <samp>mod_register_web</samp>
+ et <samp>mod_register_apps</samp>.
+</ul>
+
+<h3 id="xmpp-guide-docs"><a href="#xmpp-guide-docs">10.
+Documentations</a></h3>
+<p>Ces liens m'ont bien aid&eacute;:
+ <ul style="list-style:square">
+ <li><b>Converse.js</b>: <a
+ href="https://conversejs.org/docs/html/index.html" target="_blank"
+ rel="noopener">G&eacute;n&eacute;ral</a>, <a
+ href="https://conversejs.org/docs/html/configuration.html#configuration-settings"
+ target="_blank"
+ rel="noopener">param&eacute;trage et initialisation</a>, lire le code source HTML de la page <a
+ href="https://inverse.chat" target="_blank" rel="noopener">https://inverse.chat</a>
+
+ </li>
+ <li><b>Prosody</b>: <a
+ href="https://prosody.im/doc" target="_blank" rel="noopener">G&eacute;n&eacute;ral</a>, <a
+ href="https://prosody.im/doc/setting_up_bosh" target="_blank"
+ rel="noopener">BOSH+Nginx</a>,
+ <a href="https://prosody.im/doc/websocket" target="_blank"
+ rel="noopener">Websockets+Nginx</a>,
+ <a href="https://modules.prosody.im/xeps.html" target="_blank"
+ rel="noopener">Liens XEPs &lt;=&gt;
+ modules</a>, le <a
+ href="https://modules.prosody.im/mod_invites.html" target="_blank"
+ rel="noopener">module d'inscription via invitation</a>, le <a
+ href="https://modules.prosody.im/mod_http_upload_external.html"
+ target="_blank" rel="noopener">module d'envoi de fichiers via
+ script externe</a> et l'impl&eacute;mentation d'Holger (<a
+ href="https://github.com/weiss/ngx_http_upload" target="_blank"
+ rel="noopener">upload.pm</a>).</li>
+
+ <li><b>XMPP</b>: <a href="https://wiki.xmpp.org/">le wiki officiel</a>, <a href="https://compliance.conversations.im/">
+ tests de compliance des serveurs</a>.
+ </ul>
+
+<h3 id="xmpp-guide-thanks"><a href="#xmpp-guide-thanks">11.
+Remerciements</a></h3>
+<p>Tout ceci n'aurait pas &eacute;t&eacute; possible sans les logiciels
+libres et leurs collaborateurs. Merci &agrave; vous.<br>
+Plus sp&eacute;cifiquement:
+<ol style="list-style:square">
+ <li><a href="https://blog.laxu.de">laxu.de</a>, l'auteur de <a
+ href="https://blog.laxu.de/2018/09/08/conversejs-prosody/">
+ https://blog.laxu.de/2018/09/08/conversejs-prosody/</a>, pour le patch de
+ <samp>net/http/server.lua</samp> et les bouts de configuration nginx</li>
+ <li><a href="https://qorg11.net/">qorg</a> pour son guide sur XMPP, plus
+ particuli&egrave;rement l'"HTTP upload"
+ (<a
+ href="https://kill-9.xyz/guides/xmpp_server" target="_blank"
+ rel="noopener">https://kill-9.xyz/guides/xmpp_server</a>)</li>
+ <li> <a
+ href="https://wiki.xmpp.org/web/Jan-Carel_Brand_Application_2021"
+ target="_blank" rel="noopener">jcbrand</a>, l'auteur et
+ d&eacute;veloppeur principal de <a
+ href="https://conversejs.org/" target="_blank"
+ rel="noopener">Converse.js</a>. Tr&egrave;s r&eacute;actif aux
+ questions concernant XMPP et Converse.js dans le salon <a
+ href="xmpp:discuss@conference.conversejs.org?join">discuss@conference.conversejs.org</a>.</li>
+ <li><a href="xmpp:holger@jabber.fu-berlin.de?message">Holger Weiß</a>,
+ d&eacute;veloppeur travaillant sur le serveur XMPP ejabberd et admin du salon
+ <a
+ href="xmpp:ejabberd@conference.process-one.net?join">ejabberd@conference.process-one.net</a>
+ qui a pris de son temps pour me d&eacute;panner (<a
+ href="https://partage.les-miquelots.net/blog/un-rappel-lorsque-vous-mettez-en-place-un-serveur-xmpp-avec-prosody.html">le
+ probl&egrave;me en question</a>).</li>
+</ol><br>
+
+<p>&Agrave; bient&ocirc;t, passez une excellente journ&eacute;e et si vous
+avez des questions, remarques, suggestions ou am&eacute;liorations
+&agrave; me faire part, n'h&eacute;sitez pas &agrave; me contacter via
+mail ou XMPP &agrave; l'adresse <u>lionel ( @ ) les-miquelots ( . )
+net</u>.
+<footer>par <strong><a href='http://partage.les-miquelots.net/'>Miquel Lionel</a></strong></footer>
+</body>
+
+</html>