]> git.immae.eu Git - perso/Immae/Config/Nix.git/commitdiff
Add ejabberd service and website
authorIsmaël Bouya <ismael.bouya@normalesup.org>
Fri, 20 Dec 2019 00:55:08 +0000 (01:55 +0100)
committerIsmaël Bouya <ismael.bouya@normalesup.org>
Fri, 20 Dec 2019 03:12:30 +0000 (04:12 +0100)
modules/private/default.nix
modules/private/ejabberd/default.nix [new file with mode: 0644]
modules/private/ejabberd/ejabberd.yml [new file with mode: 0644]
modules/private/system/eldiron.nix
modules/private/websites/tools/im/default.nix [new file with mode: 0644]
modules/private/websites/tools/im/www/converse.html [new file with mode: 0644]
modules/private/websites/tools/im/www/index.html [new file with mode: 0644]
modules/private/websites/tools/tools/default.nix

index 57bad4310213587911fce7797c21a0a0f3cea871..70d4b799c8a4329d6a88a99c50190ab840e22d41 100644 (file)
@@ -47,6 +47,7 @@ set = {
   diasporaTool = ./websites/tools/diaspora;
   etherTool = ./websites/tools/ether;
   gitTool = ./websites/tools/git;
+  imTool = ./websites/tools/im;
   mastodonTool = ./websites/tools/mastodon;
   mgoblinTool = ./websites/tools/mgoblin;
   peertubeTool = ./websites/tools/peertube;
@@ -64,6 +65,7 @@ set = {
   dns = ./dns.nix;
   ftp = ./ftp.nix;
   mpd = ./mpd.nix;
+  ejabberd = ./ejabberd;
   ssh = ./ssh;
   monitoring = ./monitoring;
 
diff --git a/modules/private/ejabberd/default.nix b/modules/private/ejabberd/default.nix
new file mode 100644 (file)
index 0000000..5e717f4
--- /dev/null
@@ -0,0 +1,93 @@
+{ lib, pkgs, config, ... }:
+let
+  cfg = config.myServices.ejabberd;
+in
+{
+  options.myServices = {
+    ejabberd.enable = lib.mkOption {
+      type = lib.types.bool;
+      default = false;
+      description = ''
+        Whether to enable ejabberd service.
+      '';
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    security.acme.certs = {
+      "ejabberd" = config.myServices.certificates.certConfig // {
+        user = "ejabberd";
+        group = "ejabberd";
+        domain = "eldiron.immae.eu";
+        postRun = ''
+          systemctl restart ejabberd.service
+          '';
+        extraDomains = {
+          "immae.fr" = null;
+          "conference.immae.fr" = null;
+          "proxy.immae.fr" = null;
+          "pubsub.immae.fr" = null;
+          "upload.immae.fr" = null;
+        };
+      };
+    };
+    networking.firewall.allowedTCPPorts = [ 5222 5269 ];
+    myServices.websites.tools.im.enable = true;
+    systemd.services.ejabberd.postStop = ''
+      rm /var/log/ejabberd/erl_crash*.dump
+      '';
+    secrets.keys = [
+      {
+        dest = "ejabberd/psql.yml";
+        permissions = "0400";
+        user = "ejabberd";
+        group = "ejabberd";
+        text = ''
+          sql_type: pgsql
+          sql_server: "localhost"
+          sql_database: "${config.myEnv.jabber.postgresql.database}"
+          sql_username: "${config.myEnv.jabber.postgresql.user}"
+          sql_password: "${config.myEnv.jabber.postgresql.password}"
+          '';
+      }
+      {
+        dest = "ejabberd/host.yml";
+        permissions = "0400";
+        user = "ejabberd";
+        group = "ejabberd";
+        text = ''
+          host_config:
+            "immae.fr":
+              domain_certfile: "${config.security.acme.directory}/ejabberd/full.pem"
+              auth_method: [ldap]
+              ldap_servers: ["${config.myEnv.jabber.ldap.host}"]
+              ldap_encrypt: tls
+              ldap_rootdn: "${config.myEnv.jabber.ldap.dn}"
+              ldap_password: "${config.myEnv.jabber.ldap.password}"
+              ldap_base: "${config.myEnv.jabber.ldap.base}"
+              ldap_uids:
+                - "uid": "%u"
+                - "immaeXmppUid": "%u"
+              ldap_filter: "${config.myEnv.jabber.ldap.filter}"
+          '';
+      }
+    ];
+    users.users.ejabberd.extraGroups = [ "keys" ];
+    services.ejabberd = {
+      package = pkgs.ejabberd.override { withPgsql = true; };
+      imagemagick = true;
+      enable = true;
+      ctlConfig = ''
+        ERLANG_NODE=ejabberd@localhost
+      '';
+      configFile = pkgs.runCommand "ejabberd.yml" {
+        certificatePrivateKeyAndFullChain = "${config.security.acme.directory}/ejabberd/full.pem";
+        certificateCA = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
+        sql_config_file = config.secrets.fullPaths."ejabberd/psql.yml";
+        host_config_file = config.secrets.fullPaths."ejabberd/host.yml";
+      } ''
+        substituteAll ${./ejabberd.yml} $out
+        '';
+    };
+  };
+}
diff --git a/modules/private/ejabberd/ejabberd.yml b/modules/private/ejabberd/ejabberd.yml
new file mode 100644 (file)
index 0000000..0f678b6
--- /dev/null
@@ -0,0 +1,233 @@
+###
+###              ejabberd configuration file
+###
+### The parameters used in this configuration file are explained at
+###
+###       https://docs.ejabberd.im/admin/configuration
+###
+### The configuration file is written in YAML.
+### *******************************************************
+### *******           !!! WARNING !!!               *******
+### *******     YAML IS INDENTATION SENSITIVE       *******
+### ******* MAKE SURE YOU INDENT SECTIONS CORRECTLY *******
+### *******************************************************
+### Refer to http://en.wikipedia.org/wiki/YAML for the brief description.
+### However, ejabberd treats different literals as different types:
+###
+### - unquoted or single-quoted strings. They are called "atoms".
+###   Example: dog, 'Jupiter', '3.14159', YELLOW
+###
+### - numeric literals. Example: 3, -45.0, .0
+###
+### - quoted or folded strings.
+###   Examples of quoted string: "Lizzard", "orange".
+###   Example of folded string:
+###   > Art thou not Romeo,
+###     and a Montague?
+###
+
+hosts:
+  - "immae.fr"
+
+loglevel: 4
+log_rotate_size: 10485760
+log_rotate_date: ""
+log_rotate_count: 1
+log_rate_limit: 100
+
+certfiles:
+  - "@certificatePrivateKeyAndFullChain@"
+
+listen:
+  - 
+    port: 5222
+    ip: "::"
+    module: ejabberd_c2s
+    max_stanza_size: 262144
+    shaper: c2s_shaper
+    access: c2s
+    starttls_required: true
+  - 
+    port: 5269
+    ip: "::"
+    module: ejabberd_s2s_in
+    max_stanza_size: 524288
+  - 
+    port: 5280
+    ip: "127.0.0.1"
+    module: ejabberd_http
+    request_handlers:
+      "/admin": ejabberd_web_admin
+      "/api": mod_http_api
+      "/bosh": mod_bosh
+      "/captcha": ejabberd_captcha
+      "/upload": mod_http_upload
+      "/ws": ejabberd_http_ws
+    tls: false
+
+s2s_use_starttls: optional
+s2s_cafile: "@certificateCA@"
+
+default_db: sql
+sql_type: pgsql
+include_config_file: @sql_config_file@
+include_config_file: @host_config_file@
+new_sql_schema: true
+
+acl:
+  admin:
+    - user: "ismael@immae.fr"
+  local:
+    user_regexp: ""
+  loopback:
+    ip:
+      - "127.0.0.0/8"
+      - "::1/128"
+      - "::FFFF:127.0.0.1/128"
+
+access_rules:
+  local:
+    - allow: local
+  c2s:
+    - deny: blocked
+    - allow
+  announce:
+    - allow: admin
+  configure:
+    - allow: admin
+  muc_admin:
+    - allow: admin
+  muc_create:
+    - allow: local
+  muc:
+    - allow
+  pubsub_createnode:
+    - allow: local
+  register:
+    - deny
+  trusted_network:
+    - allow: loopback
+
+api_permissions:
+  "console commands":
+    from:
+      - ejabberd_ctl
+    who: all
+    what: "*"
+  "admin access":
+    who:
+      - acl: admin
+      - oauth:
+        - scope: "ejabberd:admin"
+        - acl: admin
+    what:
+      - "*"
+      - "!stop"
+      - "!start"
+  "public commands":
+    who:
+      - ip:
+        - "0.0.0.0"
+        - "::"
+    what:
+      - "status"
+      - "connected_users_number"
+
+shaper:
+  normal: 1000
+  fast: 50000
+
+shaper_rules:
+  max_user_sessions: 10
+  max_user_offline_messages:
+    - 5000: admin
+    - 100
+  c2s_shaper:
+    - none: admin
+    - normal
+  s2s_shaper: fast
+
+modules:
+  mod_adhoc: {}
+  mod_admin_extra: {}
+  mod_announce:
+    access: announce
+  mod_avatar: {}
+  mod_blocking: {}
+  mod_bosh: {}
+  mod_caps: {}
+  mod_carboncopy: {}
+  mod_client_state: {}
+  mod_configure: {}
+  mod_disco: {}
+  mod_fail2ban: {}
+  mod_http_api: {}
+  mod_http_upload:
+    put_url: "https://im.immae.fr/upload"
+    custom_headers:
+      "Access-Control-Allow-Origin": "*"
+      "Access-Control-Allow-Methods": "OPTIONS, HEAD, GET, PUT, POST"
+      "Access-Control-Allow-Headers": "Content-Type"
+  mod_last: {}
+  mod_mam:
+    default: always
+  mod_muc:
+    access:
+      - allow
+    access_admin:
+      - allow: admin
+    access_create: muc_create
+    access_persistent: muc_create
+    default_room_options:
+      mam: true
+  mod_muc_admin: {}
+  mod_offline:
+    access_max_user_messages: max_user_offline_messages
+  mod_ping: {}
+  mod_privacy: {}
+  mod_private: {}
+  mod_proxy65:
+    access: local
+    max_connections: 5
+  mod_pubsub:
+    access_createnode: pubsub_createnode
+    plugins:
+      - "flat"
+      - "hometree"
+      - "pep"
+    force_node_config:
+      ## Change from "whitelist" to "open" to enable OMEMO support
+      ## See https://github.com/processone/ejabberd/issues/2425
+      "eu.siacs.conversations.axolotl.*":
+        access_model: open
+      ## Avoid buggy clients to make their bookmarks public
+      "storage:bookmarks":
+        access_model: whitelist
+  mod_push: {}
+  mod_push_keepalive: {}
+  mod_register:
+    ## Only accept registration requests from the "trusted"
+    ## network (see access_rules section above).
+    ## Think twice before enabling registration from any
+    ## address. See the Jabber SPAM Manifesto for details:
+    ## https://github.com/ge0rg/jabber-spam-fighting-manifesto
+    ip_access: trusted_network
+    access: register
+  mod_roster:
+    versioning: true
+  mod_s2s_dialback: {}
+  mod_shared_roster: {}
+  mod_stats: {}
+  mod_stream_mgmt:
+    resend_on_timeout: if_offline
+  mod_time: {}
+  mod_vcard: {}
+  mod_vcard_xupdate: {}
+  mod_version:
+    show_os: false
+
+### Local Variables:
+### mode: yaml
+### End:
+### vim: set filetype=yaml tabstop=8
+
index 172e4be604f048cf4ec4821e0284409e7f038992..e1186f526b6276e9d0f471a2e9bec95a5ac18095 100644 (file)
@@ -34,6 +34,7 @@
   myServices.certificates.enable = true;
   myServices.websites.enable = true;
   myServices.mail.enable = true;
+  myServices.ejabberd.enable = true;
   services.pure-ftpd.enable = true;
   services.duplyBackup.enable = true;
 
diff --git a/modules/private/websites/tools/im/default.nix b/modules/private/websites/tools/im/default.nix
new file mode 100644 (file)
index 0000000..9744d8e
--- /dev/null
@@ -0,0 +1,37 @@
+{ config, lib, ... }:
+let
+  cfg = config.myServices.websites.tools.im;
+in
+{
+  options.myServices.websites.tools.im = {
+    enable = lib.mkEnableOption "enable im website";
+  };
+
+  config = lib.mkIf cfg.enable {
+    services.websites.env.tools.vhostConfs.im = {
+      certName   = "eldiron";
+      addToCerts = true;
+      hosts      = ["im.immae.fr"];
+      root       = ./www;
+      extraConfig = [
+        ''
+          Alias /converse ${./www}/converse.html
+          ProxyPreserveHost On
+          <Location "/bosh">
+            ProxyPass http://localhost:5280/bosh
+            ProxyPassReverse http://localhost:5280/bosh
+          </Location>
+          <Location "/ws">
+            ProxyPass ws://localhost:5280/ws
+          </Location>
+          ProxyPass /upload http://localhost:5280/upload
+          ProxyPassReverse /upload http://localhost:5280/upload
+          ProxyPass /admin http://localhost:5280/admin
+          ProxyPassReverse /admin http://localhost:5280/admin
+          ProxyPass /api http://localhost:5280/api
+          ProxyPassReverse /api http://localhost:5280/api
+          ''
+      ];
+    };
+  };
+}
diff --git a/modules/private/websites/tools/im/www/converse.html b/modules/private/websites/tools/im/www/converse.html
new file mode 100644 (file)
index 0000000..5835b6e
--- /dev/null
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html lang="en">
+        <head>
+                <title>Converse</title>
+                <meta charset="utf-8">
+                <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+                <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+                <meta name="description" content="Converse: An XMPP chat client which can be integrated into any website" />
+                <meta name="keywords" content="xmpp chat webchat converse.js Converse" />
+
+                <link type="text/css" rel="stylesheet" media="screen" href="https://cdn.conversejs.org/5.0.4/dist/converse.min.css" />
+                <style type="text/css">
+                #conversejs div.chat-msg__text pre {
+                        background-color: #eee;
+                        padding: 10px;
+                }
+                </style>
+                <script src="https://cdn.conversejs.org/3rdparty/libsignal-protocol.min.js"></script>
+                <script src="https://cdn.conversejs.org/5.0.4/dist/converse.min.js"></script>
+                <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
+                <script src="https://cdnjs.cloudflare.com/ajax/libs/markdown-it/10.0.0/markdown-it.min.js"></script>
+                <script>
+                        var md = window.markdownit({
+                                html: true,
+                        });
+                        converse.plugins.add('markdown', {
+                                //initialize () {
+                                //      const { _converse } = this;
+                                //      _converse.api.listen.on('afterMessageBodyTransformed', (view, text) => {
+                                //              let newtext = text.replace(/<br\/>/g, '\n').replace(/```/g, "\n```\n");
+                                //              newtext = md.render(newtext).replace(/^<p>/, "").replace(/<\/p>\s*$/, "");
+                                //              view.model.save({'message': newtext}, {'silent': true });
+                                //      });
+                                //}
+                                overrides: {
+                                        MessageView: {
+                                                transformBodyText: async function(text) {
+                                                        let newtext = await this.__super__.transformBodyText.apply(this, arguments);
+                                                        newtext = newtext.replace(/<br\/>/g, '\n').replace(/```/g, "\n```\n");
+                                                        return md.render(newtext).replace(/^<p>/, "").replace(/<\/p>\s*$/, "");
+                                                }
+                                        }
+                                }
+                        });
+                        converse.initialize({
+                                //bosh_service_url: 'https://im.immae.fr/bosh',
+                                websocket_url: 'wss://im.immae.fr/ws',
+                                view_mode: 'fullscreen',
+                                show_controlbox_by_default: true,
+                                whitelisted_plugins: ['markdown'],
+                        });
+                </script>
+        </head>
+        <body>
+        </body>
+</html>
+
diff --git a/modules/private/websites/tools/im/www/index.html b/modules/private/websites/tools/im/www/index.html
new file mode 100644 (file)
index 0000000..15e09f2
--- /dev/null
@@ -0,0 +1,46 @@
+<!doctype html>
+<html lang="fr">
+  <head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Instant messaging configuration (Jabber/XMPP)</title>
+    <style type="text/css">
+      body {
+        padding-top: 1em;
+        padding-left: 5px;
+        padding-right: 5px;
+        text-align: left;
+        margin: auto;
+        font: 20px Helvetica, sans-serif;
+        color: #333;
+        height: 100%;
+        min-height: 100%;
+      }
+      article {
+        text-align: justify;
+        display: block;
+        max-width: 850px;
+        margin: 0 auto;
+        padding-top: 30px;
+      }
+      span.code {
+        font-family: monospace;
+      }
+    </style>
+  </head>
+  <body>
+    <p>
+    Pre-configured clients:
+    <ul>
+      <li><a href="converse">Converse client</a></li>
+    </ul>
+    </p>
+    <p>
+    Technical details:
+    <ul>
+      <li>HTTP-bind/BOSH access (XEP-0124 / XEP-0206): <span class="code">https://im.immae.fr/bosh</span></li>
+      <li>WS access (RFC 7395): <span class="code">wss://im.immae.fr/ws</span></li>
+    </ul>
+    </p>
+  </body>
+</html>
index 5a0c196737a3a4bd4472ca9aac5f1b929923551f..02ff224f9a563147485f145c21b277b72fabde85 100644 (file)
@@ -100,6 +100,7 @@ in {
       extraConfig = [
         ''
           RedirectMatch 301 ^/roundcube(.*)$   https://mail.immae.eu/roundcube$1
+          RedirectMatch 301 ^/jappix(.*)$      https://im.immae.fr/converse
 
           <Directory "/var/lib/ftp/tools.immae.eu">
             DirectoryIndex index.php index.htm index.html
@@ -126,7 +127,7 @@ in {
     services.websites.env.tools.vhostConfs.outils = {
       certName   = "eldiron";
       addToCerts = true;
-      hosts      = [ "outils.immae.eu" ];
+      hosts      = [ "outils.immae.eu" "outils.immae.fr" ];
       root       = null;
       extraConfig = [
         ''
@@ -146,6 +147,8 @@ in {
 
         RedirectMatch 301 ^/roundcube(.*)$   https://mail.immae.eu/roundcube$1
 
+        RedirectMatch 301 ^/jappix(.*)$      https://im.immae.fr/converse
+
         RedirectMatch 301 ^/(.*)$            https://tools.immae.eu/$1
         ''
       ];