blob: ef03a00ee4a56ed4c01c6b5bf6a87e4539cce136 [file] [log] [blame]
Adrien Béraude74741b2021-04-19 13:22:54 -04001'use strict'
Larbi Gharibe9af9732021-03-31 15:08:01 +01002
Adrien Béraude74741b2021-04-19 13:22:54 -04003import dotenv from 'dotenv'
4dotenv.config()
5
6import { promises as fs } from 'fs'
7import http from 'http'
8import express from 'express'
9import session from 'express-session'
Adrien Béraud6ecaa402021-04-06 17:37:25 -040010//const cookieParser = require('cookie-parser')
11//const io = require('socket.io')(server)
Adrien Béraude74741b2021-04-19 13:22:54 -040012import path from 'path'
13import passport from 'passport'
14import { Strategy as LocalStrategy } from 'passport-local'
15//import { createRequire } from 'module';
16//const require = createRequire(import.meta.url);
17import { fileURLToPath } from 'url';
18const __filename = fileURLToPath(import.meta.url);
19const __dirname = path.dirname(__filename);
Larbi Gharibe9af9732021-03-31 15:08:01 +010020
Adrien Béraud947e8792021-04-15 18:32:44 -040021//const redis = require('redis-url').connect()
22//const RedisStore = require('connect-redis')(session)
Adrien Béraud6ecaa402021-04-06 17:37:25 -040023/*const passportSocketIo = require('passport.socketio')*/
Larbi Gharibe9af9732021-03-31 15:08:01 +010024
Adrien Béraude74741b2021-04-19 13:22:54 -040025import indexRouter from './routes/index.js'
Adrien Béraud6ecaa402021-04-06 17:37:25 -040026
Larbi Gharibe9af9732021-03-31 15:08:01 +010027//const cors = require('cors')
28
Adrien Béraude74741b2021-04-19 13:22:54 -040029import JamiRestApi from './routes/jami.js'
30import JamiDaemon from './JamiDaemon.js'
31
32const configPath = 'jamiServerConfig.json'
Larbi Gharibe9af9732021-03-31 15:08:01 +010033
Adrien Béraud6ecaa402021-04-06 17:37:25 -040034//const sessionStore = new RedisStore({ client: redis })
35const sessionStore = new session.MemoryStore()
Larbi Gharibe9af9732021-03-31 15:08:01 +010036
Adrien Béraud3b5d9a62021-04-17 18:40:27 -040037const loadConfig = async (filePath) => {
Adrien Béraude74741b2021-04-19 13:22:54 -040038 const config = {users: {}, authMethods: []}
Adrien Béraud3b5d9a62021-04-17 18:40:27 -040039 try {
Adrien Béraude74741b2021-04-19 13:22:54 -040040 return Object.assign(config, JSON.parse(await fs.readFile(filePath)))
41 } catch(e) {
42 console.log(e)
43 return config
Adrien Béraud3b5d9a62021-04-17 18:40:27 -040044 }
Adrien Béraud824a7132021-04-17 17:25:27 -040045}
46
Adrien Béraude74741b2021-04-19 13:22:54 -040047const saveConfig = (filePath, config) => {
48 return fs.writeFile(filePath, JSON.stringify(config))
49}
50
Larbi Gharibe9af9732021-03-31 15:08:01 +010051/*
Adrien Béraud3b5d9a62021-04-17 18:40:27 -040052Share sessions between Passport.js and Socket.io
Larbi Gharibe9af9732021-03-31 15:08:01 +010053*/
54
55function logSuccess() {
Adrien Béraude74741b2021-04-19 13:22:54 -040056 console.log("passportSocketIo authorized user with Success 😁")
Larbi Gharibe9af9732021-03-31 15:08:01 +010057}
58
59function logFail() {
Adrien Béraude74741b2021-04-19 13:22:54 -040060 console.log("passportSocketIo failed to authorized user 👺")
Larbi Gharibe9af9732021-03-31 15:08:01 +010061}
62
63/*
Larbi Gharibe9af9732021-03-31 15:08:01 +010064
Adrien Béraud3b5d9a62021-04-17 18:40:27 -040065tempAccounts holds users accounts while tempting to authenticate them on Jams.
66connectedUsers holds users accounts after they got authenticated by Jams.
Larbi Gharibe9af9732021-03-31 15:08:01 +010067
Adrien Béraud3b5d9a62021-04-17 18:40:27 -040068Users should be removed from connectedUsers when receiving a disconnect
69web socket call
Larbi Gharibe9af9732021-03-31 15:08:01 +010070
71*/
Adrien Béraude74741b2021-04-19 13:22:54 -040072const tempAccounts = {}
73const connectedUsers = {}
Larbi Gharibe9af9732021-03-31 15:08:01 +010074
Adrien Béraud3b5d9a62021-04-17 18:40:27 -040075const createServer = async (appConfig) => {
76 const app = express()
77 console.log(`Loading server for ${app.get('env')} with config:`)
78 console.log(appConfig)
79 const development = app.get('env') === 'development'
Larbi Gharibe9af9732021-03-31 15:08:01 +010080
Adrien Béraud3b5d9a62021-04-17 18:40:27 -040081 if (development) {
Adrien Béraude74741b2021-04-19 13:22:54 -040082 const [ webpack, webpackDev, webpackHot, webpackConfig ] = await Promise.all([
83 import('webpack'),
84 import('webpack-dev-middleware'),
85 import('webpack-hot-middleware'),
86 import('./client/webpack.config.js')
87 ])
88 const compiler = webpack.default(webpackConfig.default)
89 app.use(webpackDev.default(compiler, {
90 publicPath: webpackConfig.default.output.publicPath
91 }))
92 app.use(webpackHot.default(compiler))
Larbi Gharibe9af9732021-03-31 15:08:01 +010093 }
Larbi Gharibe9af9732021-03-31 15:08:01 +010094
Adrien Béraud3b5d9a62021-04-17 18:40:27 -040095 /*
96 Configuation for Passeport Js
97 */
Adrien Béraude74741b2021-04-19 13:22:54 -040098 app.disable('x-powered-by')
Adrien Béraud6ecaa402021-04-06 17:37:25 -040099
Adrien Béraud3b5d9a62021-04-17 18:40:27 -0400100 app.use(session({
101 store: sessionStore,
102 resave: false,
103 saveUninitialized: true,
104 cookie: {
105 secure: false,//!development,
106 maxAge: 2419200000
107 },
108 secret: process.env.SECRET_KEY_BASE
Adrien Béraude74741b2021-04-19 13:22:54 -0400109 }))
110 app.use(passport.initialize())
111 app.use(passport.session())
112 // app.use(app.router)
Adrien Béraud3b5d9a62021-04-17 18:40:27 -0400113 //app.use(cors())
Adrien Béraud6ecaa402021-04-06 17:37:25 -0400114
Adrien Béraude74741b2021-04-19 13:22:54 -0400115 const jami = new JamiDaemon()
Adrien Béraud3b5d9a62021-04-17 18:40:27 -0400116 const apiRouter = new JamiRestApi(jami).getRouter()
Adrien Béraud6ecaa402021-04-06 17:37:25 -0400117
Adrien Béraud3b5d9a62021-04-17 18:40:27 -0400118 /*
119 io.use(passportSocketIo.authorize({
120 key: 'connect.sid',
121 secret: process.env.SECRET_KEY_BASE,
122 store: sessionStore,
123 passport: passport,
124 cookieParser: cookieParser,
125 //success: logSuccess(),
126 // fail: logFail(),
Adrien Béraude74741b2021-04-19 13:22:54 -0400127 }))
Adrien Béraud3b5d9a62021-04-17 18:40:27 -0400128 */
Adrien Béraud6ecaa402021-04-06 17:37:25 -0400129
Adrien Béraude74741b2021-04-19 13:22:54 -0400130 const isSetupComplete = () => {
131 return 'admin' in appConfig.users
132 }
133
134 const accountFilter = filter => {
135 if (typeof filter === 'string') {
136 if (filter === '*')
137 return undefined
138 else
139 return account => account.getId() === filter
140 } else if (Array.isArray(filter)) {
141 return account => filter.includes(account.getId())
142 } else {
143 throw new Error('Invalid account filter string')
144 }
145 }
146
147 const user = (id, config) => {
148 return {
149 id,
150 config,
151 username: config.username || id,
152 accountFilter: accountFilter(config.accounts)
153 }
154 }
155
Adrien Béraud3b5d9a62021-04-17 18:40:27 -0400156 passport.serializeUser((user, done) => {
Adrien Béraude74741b2021-04-19 13:22:54 -0400157 connectedUsers[user.id] = user.config
158 console.log("=============================SerializeUser called " + user.id)
Adrien Béraud3b5d9a62021-04-17 18:40:27 -0400159 console.log(user)
Adrien Béraude74741b2021-04-19 13:22:54 -0400160 done(null, user.id)
161 })
Adrien Béraud6ecaa402021-04-06 17:37:25 -0400162
Adrien Béraud3b5d9a62021-04-17 18:40:27 -0400163 const deserializeUser = (id, done) => {
Adrien Béraude74741b2021-04-19 13:22:54 -0400164 console.log("=============================DeserializeUser called on: " + id)
165 const userConfig = connectedUsers[id]
166 console.log(userConfig)
167 if (userConfig) {
168 done(null, user(id, userConfig))
169 } else
170 done(404, null)
171 }
172 passport.deserializeUser(deserializeUser)
Larbi Gharibe9af9732021-03-31 15:08:01 +0100173
Adrien Béraud3b5d9a62021-04-17 18:40:27 -0400174 const jamsStrategy = new LocalStrategy(
175 (username, password, done) => {
Adrien Béraud3b5d9a62021-04-17 18:40:27 -0400176 const accountId = jami.addAccount({
177 'managerUri': 'https://jams.savoirfairelinux.com',
178 'managerUsername': username,
179 'archivePassword': password
Adrien Béraude74741b2021-04-19 13:22:54 -0400180 })
181 const id = `jams_${username}`
182 const userConfig = { username, type: 'jams', accounts: accountId }
183 const newUser = user(id, userConfig)
184 console.log("AccountId: " + accountId)
185 tempAccounts[accountId] = { done, newUser }
Larbi Gharibe9af9732021-03-31 15:08:01 +0100186
Adrien Béraud3b5d9a62021-04-17 18:40:27 -0400187 }
Adrien Béraude74741b2021-04-19 13:22:54 -0400188 )
189 jamsStrategy.name = "jams"
Adrien Béraud3b5d9a62021-04-17 18:40:27 -0400190
191 const localStrategy = new LocalStrategy(
192 (username, password, done) => {
Adrien Béraude74741b2021-04-19 13:22:54 -0400193 console.log("localStrategy: " + username + " " + password)
Adrien Béraud3b5d9a62021-04-17 18:40:27 -0400194
Adrien Béraude74741b2021-04-19 13:22:54 -0400195 const id = username
196 const userConfig = appConfig.users[username]
197 if (!userConfig) {
198 return done(null, false, { message: 'Incorrect username.' })
199 }
200 if (userConfig.password !== password) {
201 return done(null, false, { message: 'Incorrect password.' })
202 }
203 userConfig.type = 'local'
204
205 done(null, user(id, userConfig))
Adrien Béraud3b5d9a62021-04-17 18:40:27 -0400206 }
Adrien Béraude74741b2021-04-19 13:22:54 -0400207 )
Adrien Béraud3b5d9a62021-04-17 18:40:27 -0400208
Adrien Béraude74741b2021-04-19 13:22:54 -0400209 passport.use(jamsStrategy)
210 passport.use(localStrategy)
Adrien Béraud3b5d9a62021-04-17 18:40:27 -0400211
212 const secured = (req, res, next) => {
Adrien Béraude74741b2021-04-19 13:22:54 -0400213 if (req.user) {
214 return next()
Adrien Béraud3b5d9a62021-04-17 18:40:27 -0400215 }
216 res.status(401).end()
Adrien Béraude74741b2021-04-19 13:22:54 -0400217 }
Adrien Béraud3b5d9a62021-04-17 18:40:27 -0400218 const securedRedirect = (req, res, next) => {
219 if (req.user && req.user.accountId) {
Adrien Béraude74741b2021-04-19 13:22:54 -0400220 return next()
Adrien Béraud3b5d9a62021-04-17 18:40:27 -0400221 }
Adrien Béraude74741b2021-04-19 13:22:54 -0400222 req.session.returnTo = req.originalUrl
223 res.redirect('/login')
224 }
Adrien Béraud3b5d9a62021-04-17 18:40:27 -0400225
Adrien Béraude74741b2021-04-19 13:22:54 -0400226 app.use(express.json())
227 app.post('/setup', (req, res) => {
228 if (isSetupComplete()) {
229 return res.status(404).end()
230 }
231 if (!req.body.password) {
232 return res.status(400).end()
233 }
234 console.log(req.body)
235 appConfig.users.admin = {
236 "accounts": "*",
237 password: req.body.password
238 }
239 res.status(200).end()
240 saveConfig(configPath, appConfig)
241 })
242 app.post('/auth/jams', passport.authenticate('jams'), (req, res) => {
Adrien Béraud3b5d9a62021-04-17 18:40:27 -0400243 res.json({ loggedin: true })
Adrien Béraude74741b2021-04-19 13:22:54 -0400244 })
245 app.post('/auth/local', passport.authenticate('local'), (req, res) => {
246 res.json({ loggedin: true, user: req.user.id })
247 })
248 app.get('/auth', (req, res) => {
249 if (req.user) {
250 res.json({ loggedin: true, username: req.user.username, type: req.user.type })
251 } else if (isSetupComplete()) {
252 res.status(401).json({})
253 } else {
254 res.status(401).json({ setupComplete: false })
255 }
256 })
Adrien Béraud3b5d9a62021-04-17 18:40:27 -0400257
Adrien Béraude74741b2021-04-19 13:22:54 -0400258 app.use('/api', secured, apiRouter)
Adrien Béraud3b5d9a62021-04-17 18:40:27 -0400259
Adrien Béraude74741b2021-04-19 13:22:54 -0400260 app.use('/', indexRouter)
Adrien Béraud3b5d9a62021-04-17 18:40:27 -0400261
262 /* GET React App */
263
264 app.use(express.static(path.join(__dirname, 'client', 'dist')))
265
266 app.use((req, res, next) => {
Adrien Béraude74741b2021-04-19 13:22:54 -0400267 res.sendFile(path.join(__dirname, 'client', 'dist', 'index.html'))
268 })
Adrien Béraud3b5d9a62021-04-17 18:40:27 -0400269
Adrien Béraude74741b2021-04-19 13:22:54 -0400270 return http.Server(app)
Adrien Béraud3b5d9a62021-04-17 18:40:27 -0400271}
272
Adrien Béraude74741b2021-04-19 13:22:54 -0400273loadConfig(configPath)
Adrien Béraud3b5d9a62021-04-17 18:40:27 -0400274 .then(createServer)
275 .then(server => {
Adrien Béraude74741b2021-04-19 13:22:54 -0400276 server.listen(3000)
Adrien Béraud3b5d9a62021-04-17 18:40:27 -0400277 })
Larbi Gharibe9af9732021-03-31 15:08:01 +0100278
Adrien Béraud6ecaa402021-04-06 17:37:25 -0400279/*
Larbi Gharibe9af9732021-03-31 15:08:01 +0100280io.on('connection', (socket) => {
281 console.log("Client just connected !")
282 socket.on('SendMessage', (data) => {
Adrien Béraude74741b2021-04-19 13:22:54 -0400283 console.log("Message " + data.text + " sent to " + data.destinationId + " by " + socket.session.user.accountId)
284 const msgMap = new jami.dring.StringMap()
285 msgMap.set('text/plain', data.text)
286 jami.dring.sendAccountTextMessage(socket.session.user.accountId, data.destinationId, msgMap)
287 })
288})
Larbi Gharibe9af9732021-03-31 15:08:01 +0100289
Larbi Gharibe9af9732021-03-31 15:08:01 +0100290io.use((socket, next) => {
291 cookieParser(socket.handshake, {}, (err) => {
292 if (err) {
Adrien Béraude74741b2021-04-19 13:22:54 -0400293 console.log("error in parsing cookie")
294 return next(err)
Larbi Gharibe9af9732021-03-31 15:08:01 +0100295 }
296 if (!socket.handshake.signedCookies) {
Adrien Béraude74741b2021-04-19 13:22:54 -0400297 console.log("no secureCookies|signedCookies found")
298 return next(new Error("no secureCookies found"))
Larbi Gharibe9af9732021-03-31 15:08:01 +0100299 }
300 sessionStore.get(socket.handshake.signedCookies["connect.sid"], (err, session) => {
Adrien Béraude74741b2021-04-19 13:22:54 -0400301 socket.session = session
302 if (!err && !session) err = new Error('session not found')
Larbi Gharibe9af9732021-03-31 15:08:01 +0100303 if (err) {
Adrien Béraude74741b2021-04-19 13:22:54 -0400304 console.log('failed connection to socket.io:', err)
Larbi Gharibe9af9732021-03-31 15:08:01 +0100305 } else {
Adrien Béraude74741b2021-04-19 13:22:54 -0400306 console.log(session)
307 console.log('successful connection to socket.io ' + session.passport.user)
308 const userKey = session.passport.user
Larbi Gharibe9af9732021-03-31 15:08:01 +0100309 deserializeUser(userKey, (err, user) => {
310 console.log("deserializeUser: " + user)
311 if (err)
Adrien Béraude74741b2021-04-19 13:22:54 -0400312 return next(err, true)
Larbi Gharibe9af9732021-03-31 15:08:01 +0100313 if (!user)
Adrien Béraude74741b2021-04-19 13:22:54 -0400314 return next("User not found", false)
Larbi Gharibe9af9732021-03-31 15:08:01 +0100315
316 console.log("User associated socket id: " + socket.id)
Adrien Béraude74741b2021-04-19 13:22:54 -0400317 user.socketId = socket.id
318 socket.session.user = user
319 console.log("User added to session --------> " + user.accountId)
320 //auth.success(data, accept)
321 next(err, true)
322 })
Larbi Gharibe9af9732021-03-31 15:08:01 +0100323 }
Adrien Béraude74741b2021-04-19 13:22:54 -0400324 })
325 })
326})
Adrien Béraud6ecaa402021-04-06 17:37:25 -0400327*/