converted to express, with sessions, no more login proc

This commit is contained in:
STEINNI
2025-09-15 19:13:05 +00:00
parent b4cd02add5
commit e7dcb7290e
5 changed files with 126 additions and 100 deletions
+4
View File
@@ -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
View File
@@ -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
View File
@@ -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 !');
+4 -4
View File
@@ -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
View File
@@ -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) {