add initData

Change-Id: I08e5dfe42478e9ee02e48682634ecaa9ab34723b
diff --git a/app.js b/app.js
index 74c58b4..9bff634 100644
--- a/app.js
+++ b/app.js
@@ -259,13 +259,23 @@
     app.post('/auth/local', passport.authenticate('local'), (req, res) => {
         res.json({ loggedin: true, user: req.user.id })
     })
-    app.get('/auth', (req, res) => {
+
+    const getState = req => {
         if (req.user) {
-            res.json({ loggedin: true, username: req.user.username, type: req.user.type })
+            return { loggedin: true, username: req.user.username, type: req.user.type }
         } else if (isSetupComplete()) {
-            res.status(401).json({})
+            return {}
         } else {
-            res.status(401).json({ setupComplete: false })
+            return { setupComplete: false }
+        }
+    }
+
+    app.get('/auth', (req, res) => {
+        const state = getState(req)
+        if (req.user) {
+            res.json(state)
+        } else {
+            res.status(401).json(state)
         }
     })
 
@@ -278,7 +288,9 @@
     app.use(express.static(path.join(__dirname, 'client', 'dist')))
 
     app.use((req, res, next) => {
-        res.sendFile(path.join(__dirname, 'client', 'dist', 'index.html'))
+        res.render(path.join(__dirname, 'client', 'dist', 'index.ejs'), {
+            initdata: JSON.stringify(getState(req))
+        })
     })
 
     const server = http.Server(app)
diff --git a/client/src/AuthManager.js b/client/src/AuthManager.js
index d6cc6b6..83f731f 100644
--- a/client/src/AuthManager.js
+++ b/client/src/AuthManager.js
@@ -31,6 +31,12 @@
 
         this.tasks = []
         this.onAuthChanged = undefined
+
+        if (initData) {
+            console.log("Using static initData")
+            this.setInitData(initData)
+            return
+        }
     }
 
     isAuthenticated() {
@@ -41,37 +47,51 @@
         return this.state
     }
 
+    setInitData(data) {
+        this.authenticating = false
+        this.state.initialized = true
+        if (data.username) {
+            Object.assign(this.state, {
+                authenticated: true,
+                setupComplete: true,
+                error: false,
+                user: { username: data.username, type: data.type }
+            })
+        } else {
+            Object.assign(this.state, {
+                authenticated: false,
+                setupComplete: 'setupComplete' in data ? data.setupComplete : true,
+                error: false
+            })
+        }
+        console.log("Init ended")
+        /*if (this.onAuthChanged)
+            this.onAuthChanged(this.state)*/
+    }
+
     init(cb) {
         this.onAuthChanged = cb
         if (this.state.initialized || this.authenticating)
             return
-        console.log("Init")
+        /*if (initData) {
+            console.log("Using static initData")
+            this.setInitData(initData)
+            return
+        }*/
         this.authenticating = true
         fetch('/auth')
             .then(async (response) => {
                 this.authenticating = false
                 this.state.initialized = true
-                console.log("Init ended")
                 if (response.status === 200) {
-                    const jsonData = await response.json()
-                    Object.assign(this.state, {
-                        authenticated: true,
-                        setupComplete: true,
-                        error: false,
-                        user: { username: jsonData.username, type: jsonData.type }
-                    })
+                    this.setInitData(await response.json())
                 } else if (response.status === 401) {
-                    const jsonData = await response.json()
-                    Object.assign(this.state, {
-                        authenticated: false,
-                        setupComplete: 'setupComplete' in jsonData ? jsonData.setupComplete : true,
-                        error: false
-                    })
+                    this.setInitData(await response.json())
                 } else {
                     this.state.error = true
+                    if (this.onAuthChanged)
+                        this.onAuthChanged(this.state)
                 }
-                if (this.onAuthChanged)
-                    this.onAuthChanged(this.state)
             }).catch(e => {
                 this.authenticating = false
                 console.log(e)
@@ -124,7 +144,9 @@
                 while (this.tasks.length !== 0) {
                     const task = this.tasks.shift()
                     if (this.state.authenticated)
-                        fetch(task.url, task.init).then(res => task.resolve(res))
+                        fetch(task.url, task.init)
+                        .then(res => task.resolve(res))
+                        .catch(e => console.log("Error executing pending task: " + e))
                     else
                         task.reject(new Error("Authentication failed"))
                 }
diff --git a/client/src/index.ejs b/client/src/index.ejs
index 162d470..bfe8174 100644
--- a/client/src/index.ejs
+++ b/client/src/index.ejs
@@ -7,6 +7,7 @@
   <link rel="apple-touch-icon" href="/logo192.png" />
   <meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width" />
   <meta name="description" content="Web site created using create-react-app" />
+  <script>const initData=<%- initdata %></script>
   <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
   <title>Jami Web Node</title>
 </head>
diff --git a/client/src/pages/accountSelection.jsx b/client/src/pages/accountSelection.jsx
index 0cd9e29..c95b02b 100644
--- a/client/src/pages/accountSelection.jsx
+++ b/client/src/pages/accountSelection.jsx
@@ -7,8 +7,10 @@
 import ListItemLink from '../components/ListItemLink';
 import ConversationAvatar from '../components/ConversationAvatar';
 import { AddRounded } from '@material-ui/icons';
+import { useHistory } from 'react-router';
 
 const AccountSelection = (props) => {
+  const history = useHistory()
   const [state, setState] = useState({
     loaded: false,
     error: false,
@@ -21,10 +23,14 @@
       .then(res => res.json())
       .then(result => {
         console.log(result)
-        setState({
-          loaded: true,
-          accounts: result.map(account => Account.from(account)),
-        })
+        if (result.length === 0) {
+          history.replace('/newAccount')
+        } else {
+          setState({
+            loaded: true,
+            accounts: result.map(account => Account.from(account)),
+          })
+        }
       }, error => {
         console.log(`get error ${error}`)
         setState({
diff --git a/client/src/pages/serverSetup.jsx b/client/src/pages/serverSetup.jsx
index 29e4ea5..703f842 100644
--- a/client/src/pages/serverSetup.jsx
+++ b/client/src/pages/serverSetup.jsx
@@ -1,9 +1,9 @@
-import React, { useState } from 'react';
-import { useHistory } from "react-router-dom";
+import React, { useState } from 'react'
+import { useHistory } from "react-router-dom"
 
-import { Box, Container, Fab, Card, CardContent, Typography, Input } from '@material-ui/core';
-import GroupAddRounded from '@material-ui/icons/GroupAddRounded';
-import { makeStyles } from '@material-ui/core/styles';
+import { Box, Container, Fab, Card, CardContent, Typography, Input } from '@material-ui/core'
+import GroupAddRounded from '@material-ui/icons/GroupAddRounded'
+import { makeStyles } from '@material-ui/core/styles'
 import authManager from '../AuthManager'
 
 const useStyles = makeStyles((theme) => ({
@@ -26,21 +26,19 @@
 
 export default function ServerSetup(props) {
   const classes = useStyles()
-  const history = useHistory();
-  const [password, setPassword] = useState('');
-  const [passwordRepeat, setPasswordRepeat] = useState('');
-  const [loading, setLoading] = useState(false);
+  const history = useHistory()
+  const [password, setPassword] = useState('')
+  const [passwordRepeat, setPasswordRepeat] = useState('')
+  const [loading, setLoading] = useState(false)
 
   const isValid = () => password && password === passwordRepeat
 
-  const handleSubmit = async e => {
+  const handleSubmit = e => {
     e.preventDefault()
     setLoading(true)
     if (!isValid())
       return
-    if (await authManager.setup(password)) {
-      history.replace('/')
-    }
+    authManager.setup(password)
   }
 
   return (
diff --git a/client/webpack.config.js b/client/webpack.config.js
index 7a2a6de..beb3a23 100644
--- a/client/webpack.config.js
+++ b/client/webpack.config.js
@@ -15,7 +15,7 @@
 
 let entry = [resolve(__dirname, 'src', 'index.js')]
 let plugins = [
-  new HtmlWebpackPlugin({ template: resolve(__dirname, 'src', 'index.ejs') }),
+  new HtmlWebpackPlugin({ template: '!!raw-loader!' + resolve(__dirname, 'src', 'index.ejs'), filename: 'index.ejs' }),
   new CopyWebpackPlugin({
     patterns: [{ from: resolve(__dirname, 'public'), to: resolve(__dirname, 'dist') }]
   })
diff --git a/package-lock.json b/package-lock.json
index 22d472e..27ba682 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,6 +15,7 @@
         "core-js": "^3.10.1",
         "cors": "^2.8.5",
         "dotenv": "^8.2.0",
+        "ejs": "^3.1.6",
         "env": "0.0.2",
         "express": "^4.17.1",
         "express-session": "^1.17.1",
@@ -29,11 +30,13 @@
         "jami-web-client": "file:client",
         "llnode": "^3.2.0",
         "nodemon": "^2.0.7",
+        "raw-loader": "^4.0.2",
         "webpack-dev-middleware": "^4.1.0",
         "webpack-hot-middleware": "^2.25.0"
       }
     },
     "client": {
+      "name": "jami-web-client",
       "version": "0.1.0",
       "dev": true,
       "dependencies": {
@@ -2988,6 +2991,11 @@
         "node": ">=8"
       }
     },
+    "node_modules/async": {
+      "version": "0.9.2",
+      "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz",
+      "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0="
+    },
     "node_modules/atob": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
@@ -3129,8 +3137,7 @@
     "node_modules/balanced-match": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
-      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
-      "dev": true
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
     },
     "node_modules/base64-arraybuffer": {
       "version": "0.1.4",
@@ -3227,7 +3234,6 @@
       "version": "1.1.11",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
       "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
-      "dev": true,
       "dependencies": {
         "balanced-match": "^1.0.0",
         "concat-map": "0.0.1"
@@ -3542,8 +3548,7 @@
     "node_modules/concat-map": {
       "version": "0.0.1",
       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
-      "dev": true
+      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
     },
     "node_modules/configstore": {
       "version": "5.0.1",
@@ -4057,6 +4062,20 @@
       "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
       "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
     },
+    "node_modules/ejs": {
+      "version": "3.1.6",
+      "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.6.tgz",
+      "integrity": "sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==",
+      "dependencies": {
+        "jake": "^10.6.1"
+      },
+      "bin": {
+        "ejs": "bin/cli.js"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/electron-to-chromium": {
       "version": "1.3.742",
       "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.742.tgz",
@@ -4282,7 +4301,6 @@
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
       "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
-      "dev": true,
       "engines": {
         "node": ">=0.8.0"
       }
@@ -4534,6 +4552,14 @@
       "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
       "dev": true
     },
+    "node_modules/filelist": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz",
+      "integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==",
+      "dependencies": {
+        "minimatch": "^3.0.4"
+      }
+    },
     "node_modules/fill-range": {
       "version": "7.0.1",
       "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@@ -4782,7 +4808,6 @@
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
       "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
-      "dev": true,
       "engines": {
         "node": ">=4"
       }
@@ -5289,6 +5314,60 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/jake": {
+      "version": "10.8.2",
+      "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz",
+      "integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==",
+      "dependencies": {
+        "async": "0.9.x",
+        "chalk": "^2.4.2",
+        "filelist": "^1.0.1",
+        "minimatch": "^3.0.4"
+      },
+      "bin": {
+        "jake": "bin/cli.js"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/jake/node_modules/ansi-styles": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "dependencies": {
+        "color-convert": "^1.9.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/jake/node_modules/chalk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+      "dependencies": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/jake/node_modules/color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dependencies": {
+        "color-name": "1.1.3"
+      }
+    },
+    "node_modules/jake/node_modules/color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
+    },
     "node_modules/jami-web-client": {
       "resolved": "client",
       "link": true
@@ -6074,7 +6153,6 @@
       "version": "3.0.4",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
       "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
-      "dev": true,
       "dependencies": {
         "brace-expansion": "^1.1.7"
       },
@@ -6860,6 +6938,26 @@
         "node": ">= 0.8"
       }
     },
+    "node_modules/raw-loader": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-4.0.2.tgz",
+      "integrity": "sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==",
+      "dev": true,
+      "dependencies": {
+        "loader-utils": "^2.0.0",
+        "schema-utils": "^3.0.0"
+      },
+      "engines": {
+        "node": ">= 10.13.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/webpack"
+      },
+      "peerDependencies": {
+        "webpack": "^4.0.0 || ^5.0.0"
+      }
+    },
     "node_modules/rc": {
       "version": "1.2.8",
       "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
@@ -7902,7 +8000,6 @@
       "version": "5.5.0",
       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
       "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
-      "dev": true,
       "dependencies": {
         "has-flag": "^3.0.0"
       },
@@ -10897,6 +10994,11 @@
       "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
       "dev": true
     },
+    "async": {
+      "version": "0.9.2",
+      "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz",
+      "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0="
+    },
     "atob": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
@@ -11004,8 +11106,7 @@
     "balanced-match": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
-      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
-      "dev": true
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
     },
     "base64-arraybuffer": {
       "version": "0.1.4",
@@ -11081,7 +11182,6 @@
       "version": "1.1.11",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
       "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
-      "dev": true,
       "requires": {
         "balanced-match": "^1.0.0",
         "concat-map": "0.0.1"
@@ -11327,8 +11427,7 @@
     "concat-map": {
       "version": "0.0.1",
       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
-      "dev": true
+      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
     },
     "configstore": {
       "version": "5.0.1",
@@ -11732,6 +11831,14 @@
       "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
       "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
     },
+    "ejs": {
+      "version": "3.1.6",
+      "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.6.tgz",
+      "integrity": "sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==",
+      "requires": {
+        "jake": "^10.6.1"
+      }
+    },
     "electron-to-chromium": {
       "version": "1.3.742",
       "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.742.tgz",
@@ -11908,8 +12015,7 @@
     "escape-string-regexp": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
-      "dev": true
+      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
     },
     "eslint-scope": {
       "version": "5.1.1",
@@ -12102,6 +12208,14 @@
       "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
       "dev": true
     },
+    "filelist": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz",
+      "integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==",
+      "requires": {
+        "minimatch": "^3.0.4"
+      }
+    },
     "fill-range": {
       "version": "7.0.1",
       "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@@ -12288,8 +12402,7 @@
     "has-flag": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
-      "dev": true
+      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
     },
     "has-symbols": {
       "version": "1.0.2",
@@ -12681,6 +12794,50 @@
       "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
       "dev": true
     },
+    "jake": {
+      "version": "10.8.2",
+      "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz",
+      "integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==",
+      "requires": {
+        "async": "0.9.x",
+        "chalk": "^2.4.2",
+        "filelist": "^1.0.1",
+        "minimatch": "^3.0.4"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "3.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+          "requires": {
+            "color-convert": "^1.9.0"
+          }
+        },
+        "chalk": {
+          "version": "2.4.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+          "requires": {
+            "ansi-styles": "^3.2.1",
+            "escape-string-regexp": "^1.0.5",
+            "supports-color": "^5.3.0"
+          }
+        },
+        "color-convert": {
+          "version": "1.9.3",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+          "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+          "requires": {
+            "color-name": "1.1.3"
+          }
+        },
+        "color-name": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
+        }
+      }
+    },
     "jami-web-client": {
       "version": "file:client",
       "requires": {
@@ -13388,7 +13545,6 @@
       "version": "3.0.4",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
       "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
-      "dev": true,
       "requires": {
         "brace-expansion": "^1.1.7"
       }
@@ -13979,6 +14135,16 @@
         "unpipe": "1.0.0"
       }
     },
+    "raw-loader": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-4.0.2.tgz",
+      "integrity": "sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==",
+      "dev": true,
+      "requires": {
+        "loader-utils": "^2.0.0",
+        "schema-utils": "^3.0.0"
+      }
+    },
     "rc": {
       "version": "1.2.8",
       "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
@@ -14785,7 +14951,6 @@
       "version": "5.5.0",
       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
       "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
-      "dev": true,
       "requires": {
         "has-flag": "^3.0.0"
       }
diff --git a/package.json b/package.json
index 4097c5f..ecee8fb 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
     "core-js": "^3.10.1",
     "cors": "^2.8.5",
     "dotenv": "^8.2.0",
+    "ejs": "^3.1.6",
     "env": "0.0.2",
     "express": "^4.17.1",
     "express-session": "^1.17.1",
@@ -25,6 +26,7 @@
     "jami-web-client": "file:client",
     "llnode": "^3.2.0",
     "nodemon": "^2.0.7",
+    "raw-loader": "^4.0.2",
     "webpack-dev-middleware": "^4.1.0",
     "webpack-hot-middleware": "^2.25.0"
   },