converted to express, with sessions, no more login proc
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
"dependencies": {
|
||||
"ajv": "^8.12.0",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"express": "^5.1.0",
|
||||
"express-mysql-session": "^3.0.3",
|
||||
"express-session": "^1.18.2",
|
||||
"pm2": "^6.0.10",
|
||||
@@ -23,5 +24,8 @@
|
||||
"urldecode": "^1.0.1",
|
||||
"ws": "^8.8.1",
|
||||
"yargs": "^17.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"wscat": "^6.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
+6
-42
@@ -25,33 +25,15 @@ export class WssConnexion {
|
||||
this.socket.on('message', this.receive.bind(this));
|
||||
|
||||
if(this.debug) console.log(`Spawned new WSS connection to client: ${this.req.socket.remoteAddress}:${this.req.socket.remotePort}`)
|
||||
console.log('Session infos:',this.socket.session.authenticated, this.socket.session.userInfos)
|
||||
|
||||
}
|
||||
|
||||
|
||||
doLogin(){
|
||||
this.cnxState = 'LOGIN' // then CONNECTED
|
||||
this.challenge = crypto.randomUUID()
|
||||
this.challengeTimeout = setTimeout(() => {
|
||||
if(this.debug) console.warn(`Timeout waiting for login response for UUID ${this.uuid}, closing connection !`);
|
||||
this.close()
|
||||
}, this.config.server.challengeExpiration*1000)
|
||||
this.send(JSON.stringify({
|
||||
'action': 'LOGIN',
|
||||
'challenge': this.challenge
|
||||
}));
|
||||
if(this.debug) console.log(`Sent LOGIN for UUID ${this.uuid} ==> challenge=${this.challenge}`)
|
||||
return(new Promise((resolve, reject) => {
|
||||
this.resolveLogin = resolve
|
||||
}))
|
||||
}
|
||||
|
||||
welcome(){
|
||||
clearTimeout(this.challengeTimeout)
|
||||
this.challengeTimeout = null
|
||||
this.cnxState = 'CONNECTED'
|
||||
if(this.debug) console.log(`Welcome to UUID ${this.uuid}`)
|
||||
this.resolveLogin()
|
||||
}
|
||||
|
||||
async checkLogin(userInfo, otp){
|
||||
@@ -98,31 +80,13 @@ export class WssConnexion {
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.cnxState == 'LOGIN'){
|
||||
if((action=='LOGIN') && pdata.userInfo && pdata.otp) {
|
||||
if(this.debug) console.log(`received login response : user=${pdata.userInfo} otp=${pdata.otp}`)
|
||||
if(await this.checkLogin(pdata.userInfo, pdata.otp)) {
|
||||
this.userId = pdata.userInfo
|
||||
this.welcome()
|
||||
} else {
|
||||
if(this.debug) console.warn(`Bad OTP response to login request for uuid ${this.uuid}`);
|
||||
this.send(JSON.stringify({
|
||||
'action': 'LOGIN',
|
||||
'logged': false
|
||||
}));
|
||||
this.close()
|
||||
}
|
||||
} else {
|
||||
if(this.debug) console.warn(`Invalid response to login request for uuid ${this.uuid}`,pdata);
|
||||
}
|
||||
if(typeof this['action_'+action] == "function") {
|
||||
if((this.debug) && (action != 'PONG')) console.warn(`${action} for uuid ${this.uuid}`);
|
||||
this['action_'+action](action, payload, reqid);
|
||||
} else {
|
||||
if(typeof this['action_'+action] == "function") {
|
||||
if((this.debug) && (action != 'PONG')) console.warn(`${action} for uuid ${this.uuid}`);
|
||||
this['action_'+action](action, payload, reqid);
|
||||
} else {
|
||||
if(this.debug) console.warn(`Unknown action ${action} for UUID ${this.uuid}`);
|
||||
}
|
||||
if(this.debug) console.warn(`Unknown action ${action} for UUID ${this.uuid}`);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
send(data) { // Send to Websocket
|
||||
|
||||
+85
-30
@@ -1,12 +1,14 @@
|
||||
import yargs from 'yargs/yargs'
|
||||
import { hideBin } from 'yargs/helpers'
|
||||
|
||||
import mysql from 'mysql2/promise'
|
||||
import { WebSocketServer } from 'ws'
|
||||
import fs from 'fs'
|
||||
import {RedisConnexion} from './redisConnexion.js'
|
||||
import urlparser from 'url'
|
||||
import {wssServer} from './wssServer.js'
|
||||
import {configHelper} from './configHelper.js'
|
||||
import express from 'express'
|
||||
import session from 'express-session'
|
||||
import connectMySQL from 'express-mysql-session'
|
||||
|
||||
const argv = yargs(hideBin(process.argv)).command('wssGateway', 'Redis <=> Websocket message bus gateway', {})
|
||||
.options({
|
||||
@@ -19,6 +21,56 @@ const argv = yargs(hideBin(process.argv)).command('wssGateway', 'Redis <=> Webso
|
||||
|
||||
const debug = Boolean(process.env.DEBUG) || argv.debug
|
||||
|
||||
const MySQLStore = connectMySQL(session)
|
||||
|
||||
const app = express();
|
||||
app.set('trust proxy', 1) // trust first proxy (nginx), so we serve http to nginx, but we still behave as if we're in https
|
||||
app.use(express.json())
|
||||
|
||||
const mysqlCreds = {
|
||||
// host: '127.0.0.1',
|
||||
// port: 3306,
|
||||
socketPath: '/var/run/mysqld/mysqld.sock',
|
||||
user: 'p42',
|
||||
password: 'C3h=V9!r>Mvc>skxPf9?W2P3duJTk',
|
||||
database: 'p42',
|
||||
waitForConnections: true,
|
||||
connectionLimit: 10,
|
||||
queueLimit: 0
|
||||
}
|
||||
|
||||
const db = await mysql.createConnection(mysqlCreds)
|
||||
|
||||
const sessionStore = new MySQLStore({
|
||||
createDatabaseTable: false,
|
||||
clearExpired: true,
|
||||
schema: {
|
||||
tableName: 'p42_sessions',
|
||||
columnNames: {
|
||||
session_id: 'session_id',
|
||||
expires: 'expires',
|
||||
data: 'data'
|
||||
}
|
||||
}
|
||||
}, db)
|
||||
|
||||
|
||||
const sessionParser = session({
|
||||
name: 'p42.api.sid',
|
||||
secret: 'qNhy555Y9vyxj?!3yaYA=aKfgk+Wy5eymNtP*?4i',
|
||||
store: sessionStore,
|
||||
resave: false,
|
||||
saveUninitialized: false,
|
||||
cookie: {
|
||||
maxAge: 1000 * 60 * 60 * 4,
|
||||
secure: true, //See trust proxy above
|
||||
sameSite: 'lax',
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
app.use(sessionParser)
|
||||
|
||||
const cfgh = new configHelper({
|
||||
localfile: './wssGatewayConfig.json',
|
||||
})
|
||||
@@ -43,6 +95,7 @@ cfgh.fetchConfig().then( async wssGatewayConfig => {
|
||||
console.error('Cannot get a valid configuration ! Aaarrghhh...')
|
||||
process.exit()
|
||||
}
|
||||
|
||||
let httpLib
|
||||
if(wssGatewayConfig.server.unsecure) httpLib = await import('http')
|
||||
else httpLib = await import('https')
|
||||
@@ -58,42 +111,44 @@ cfgh.fetchConfig().then( async wssGatewayConfig => {
|
||||
};
|
||||
} else options = {}
|
||||
|
||||
const httpRequestsHandler = function(request, res) {
|
||||
let parsedUrl
|
||||
try{
|
||||
parsedUrl = new urlparser.URL(request.url, `http${wssGatewayConfig.server.unsecure ? '': 's'}://${request.headers.host}`);
|
||||
} catch(e) {
|
||||
res.end()
|
||||
return
|
||||
}
|
||||
if(parsedUrl.pathname === wssGatewayConfig.server.healthCheckPath) {
|
||||
//if(debug) console.log('Got a Health-Check Request')
|
||||
res.end(JSON.stringify({
|
||||
status: 'Healthy!',
|
||||
}))
|
||||
}
|
||||
}
|
||||
const HTTPserver = httpLib.createServer(app)
|
||||
|
||||
const HTTPserver = httpLib.createServer(options, httpRequestsHandler)
|
||||
.listen(Number(wssGatewayConfig.server.listenPort),
|
||||
wssGatewayConfig.server.listenHost ? wssGatewayConfig.server.listenHost : undefined,
|
||||
function (req, res) {
|
||||
console.log(`HTTP${wssGatewayConfig.server.unsecure ? '': 'S'} now listening on ${wssGatewayConfig.server.listenHost}:${wssGatewayConfig.server.listenPort}\n`+
|
||||
`Websocket served at ${wssGatewayConfig.server.listenPath}\n`+
|
||||
`Healthcheck served at ${wssGatewayConfig.server.healthCheckPath}`)
|
||||
});
|
||||
|
||||
// Start serving WSS
|
||||
const wssServerOptions = {
|
||||
server: HTTPserver,
|
||||
path: wssGatewayConfig.server.listenPath,
|
||||
// server: HTTPserver,
|
||||
// path: wssGatewayConfig.server.listenPath,
|
||||
noServer: true
|
||||
}
|
||||
if(!wssGatewayConfig.server.unsecure) {
|
||||
wssServerOptions['key'] = fs.readFileSync(wssGatewayConfig.server.certKeyFile)
|
||||
wssServerOptions['cert'] = fs.readFileSync(wssGatewayConfig.server.certFile)
|
||||
}
|
||||
const WSSServer = new WebSocketServer(wssServerOptions);
|
||||
console.log(`WS${wssGatewayConfig.server.unsecure ? '': 'S'} server created for ${wssGatewayConfig.server.listenHost}:${wssGatewayConfig.server.listenPort}`)
|
||||
|
||||
HTTPserver.on('upgrade', (req, socket, head) => {
|
||||
sessionParser(req, {}, () => {
|
||||
if (!req.session) {
|
||||
console.warn('No session, bye bye!')
|
||||
socket.destroy()
|
||||
return
|
||||
}
|
||||
WSSServer.handleUpgrade(req, socket, head, (ws) => {
|
||||
ws.session = req.session // direct access to Express session
|
||||
WSSServer.emit('connection', ws, req)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// WSSServer.on('connection', (ws, req) => {
|
||||
// console.log('WS connected with session:', ws.session, ws.session.authenticated, ws.session.userInfos)
|
||||
// // modify session if you want
|
||||
// ws.session.views = (ws.session.views || 0) + 1
|
||||
// ws.session.save()
|
||||
// ws.send(`You visited ${ws.session.views} times`)
|
||||
// })
|
||||
|
||||
HTTPserver.listen(wssGatewayConfig.server.listenPort, () => {
|
||||
console.log(`WS${wssGatewayConfig.server.unsecure ? '': 'S'} server created for ${wssGatewayConfig.server.listenHost}:${wssGatewayConfig.server.listenPort}`)
|
||||
})
|
||||
|
||||
startRedis(wssGatewayConfig).then((rediscnx) => {
|
||||
if(debug) console.log('Redis started & logged in !');
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"serviceName": "wssGateway",
|
||||
"server": {
|
||||
"listenHost": "0.0.0.0",
|
||||
"listenHost": "127.0.0.1",
|
||||
"listenPort": 3999,
|
||||
"listenPath": "/msgbus",
|
||||
"keepAliveInterval": "30",
|
||||
"keepAliveTimeout": "5",
|
||||
"certFile": "/etc/letsencrypt/live/42.internike.com/fullchain.pem",
|
||||
"certKeyFile": "/etc/letsencrypt/live/42.internike.com/privkey.pem",
|
||||
"XXcertFile": "/etc/letsencrypt/live/42.internike.com/fullchain.pem",
|
||||
"XXcertKeyFile": "/etc/letsencrypt/live/42.internike.com/privkey.pem",
|
||||
"challengeExpiration": 20,
|
||||
"unsecure": false,
|
||||
"unsecure": true,
|
||||
"healthCheckPath": "/status",
|
||||
"devotpToken": "qhsdfkjhqsgdfkqhs",
|
||||
"systemChannels": {
|
||||
|
||||
+27
-24
@@ -1,8 +1,6 @@
|
||||
import {AccesRights} from './accesRights.js'
|
||||
import crypto from 'crypto'
|
||||
import {WssConnexion} from './wssConnexion.js'
|
||||
import session from 'express-session'
|
||||
import connectMySQL from 'express-mysql-session'
|
||||
|
||||
export class wssServer {
|
||||
|
||||
@@ -32,29 +30,34 @@ export class wssServer {
|
||||
|
||||
newWSSConnexion(socket, req) {
|
||||
var uuid = crypto.randomUUID();
|
||||
var wssCnx = new WssConnexion({
|
||||
socket: socket,
|
||||
req, req,
|
||||
uuid: uuid,
|
||||
wssSrv: this,
|
||||
debug: this.debug,
|
||||
config: this.wssGatewayConfig,
|
||||
rediscnx: this.REDIScnx,
|
||||
accessRights: this.accessRights,
|
||||
});
|
||||
this.AllWssConnections[uuid] = wssCnx;
|
||||
wssCnx.doLogin().then(() => { // Things to execute only when successfuly logged-in
|
||||
if(!(wssCnx.userId in this.Users2uuids)) this.Users2uuids[wssCnx.userId] = new Set();
|
||||
this.Users2uuids[wssCnx.userId].add(uuid);
|
||||
this.OnlineUsers.add(wssCnx.userId);
|
||||
this.REDIScnx.wssConnections[uuid] = wssCnx;
|
||||
//}).then(() => {
|
||||
wssCnx.send(JSON.stringify({
|
||||
'action': 'LOGIN',
|
||||
'logged': true
|
||||
}))
|
||||
if(socket.session && socket.session.authenticated && socket.session.userInfos && socket.session.userInfos.username){
|
||||
var wssCnx = new WssConnexion({
|
||||
socket: socket,
|
||||
req, req,
|
||||
uuid: uuid,
|
||||
wssSrv: this,
|
||||
debug: this.debug,
|
||||
config: this.wssGatewayConfig,
|
||||
rediscnx: this.REDIScnx,
|
||||
accessRights: this.accessRights,
|
||||
});
|
||||
this.AllWssConnections[uuid] = wssCnx;
|
||||
this.postLoginActions(wssCnx)
|
||||
})
|
||||
} else socket.close()
|
||||
|
||||
|
||||
// wssCnx.doLogin().then(() => { // Things to execute only when successfuly logged-in
|
||||
// if(!(wssCnx.userId in this.Users2uuids)) this.Users2uuids[wssCnx.userId] = new Set();
|
||||
// this.Users2uuids[wssCnx.userId].add(uuid);
|
||||
// this.OnlineUsers.add(wssCnx.userId);
|
||||
// this.REDIScnx.wssConnections[uuid] = wssCnx;
|
||||
// //}).then(() => {
|
||||
// wssCnx.send(JSON.stringify({
|
||||
// 'action': 'LOGIN',
|
||||
// 'logged': true
|
||||
// }))
|
||||
// this.postLoginActions(wssCnx)
|
||||
// })
|
||||
}
|
||||
|
||||
postLoginActions(wssCnx) {
|
||||
|
||||
Reference in New Issue
Block a user