Last active
December 4, 2020 06:58
-
-
Save aslamanver/e051a5d9671483732a15076259baca32 to your computer and use it in GitHub Desktop.
Pure JavaScript WebSocket Server with Ping-Pong, Handshake Upgrade, AES Encrypt, Decrypt and Authentication functionalities.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const express = require("express") | |
const WebSocket = require('ws') | |
const app = express() | |
const server = require('http').createServer(app) | |
const wss = new WebSocket.Server({ noServer: true }) | |
const wschandler = require('./wschandler').from(wss, server) | |
wss.on('connection', (ws, req) => { | |
console.log('connection', req.socket.remoteAddress, ws.data.token) | |
ws.on('close', (reason) => { | |
console.log('close', req.socket.remoteAddress, ws.data.token) | |
}) | |
ws.on('message', (message) => { | |
console.log('message', message, ws.data.token) | |
}) | |
}) | |
app.get('/', (req, res) => { | |
res.sendStatus(200) | |
}) | |
server.listen(3002, () => console.log(`Server is running at 0.0.0.0:3002`)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const url = require('url') | |
const CryptoJS = require("crypto-js") | |
class WSCHandler { | |
constructor() { | |
this.wss | |
this.server | |
} | |
from(wss, server) { | |
this.wss = wss | |
this.server = server | |
this.server.on('upgrade', (req, socket, head) => { | |
console.log('upgrade', socket.remoteAddress, req.url) | |
this.wssauthenticate(req, (client, error) => { | |
if (error || !client) { | |
let headers = 'HTTP/1.1 401 Unauthorized\r\n' | |
if (error === 429) headers = 'HTTP/1.1 429 Too Many Requests\r\n' | |
headers += 'Connection: close\r\n' | |
socket.write(headers + '\r\n') | |
socket.destroy() | |
} else { | |
this.wss.handleUpgrade(req, socket, head, (ws) => { | |
ws.data = client | |
ws.isAlive = true; | |
ws.on('pong', () => { | |
console.log('pong-from', JSON.stringify(ws.data)) | |
ws.isAlive = true | |
}) | |
this.wss.emit('connection', ws, req) | |
}) | |
} | |
}) | |
}) | |
setInterval(() => { | |
console.log('ping-clients', this.wss.clients.size) | |
this.wss.clients.forEach((ws) => { | |
if (ws.isAlive === false) return ws.terminate() | |
ws.isAlive = false | |
ws.ping(() => { }) | |
}) | |
}, 10000) | |
} | |
wssauthenticate(req, callback) { | |
const query = url.parse(req.url, true).query; | |
const device = this.decrypt(query.device) | |
const token = this.decrypt(query.token) | |
const pos = query.pos | |
const client = { token, device, pos } | |
console.log('wssauthenticate', client) | |
if (client.token !== 'AUTH4ECR2PAYABLE') { | |
callback(null, 401) | |
} else if (Array.from(this.wss.clients).findIndex(ws => ws.data.pos === client.pos && ws.data.device === client.device && ws.data.token === client.token) > -1) { | |
callback(null, 429) | |
} else { | |
callback(client) | |
} | |
} | |
encrypt(data) { | |
if (!data) return null | |
try { | |
return CryptoJS.AES.encrypt(data, CryptoJS.enc.Utf8.parse("NdRgUkXp2s5v8y/A"), { | |
mode: CryptoJS.mode.ECB, | |
padding: CryptoJS.pad.Pkcs7 | |
}).toString(); | |
} catch { | |
return null | |
} | |
} | |
decrypt(data) { | |
if (!data) return null | |
try { | |
return CryptoJS.AES.decrypt(data, CryptoJS.enc.Utf8.parse("NdRgUkXp2s5v8y/A"), { | |
mode: CryptoJS.mode.ECB, | |
padding: CryptoJS.pad.Pkcs7 | |
}).toString(CryptoJS.enc.Utf8) | |
} catch { | |
return null | |
} | |
} | |
} | |
module.exports = new WSCHandler(); | |
// const encrypt = (data) => { | |
// if (!data) return null | |
// try { | |
// return CryptoJS.AES.encrypt(data, CryptoJS.enc.Utf8.parse("NdRgUkXp2s5v8y/A"), { | |
// mode: CryptoJS.mode.ECB, | |
// padding: CryptoJS.pad.Pkcs7 | |
// }).toString(); | |
// } catch { | |
// return null | |
// } | |
// } | |
// const decrypt = (data) => { | |
// if (!data) return null | |
// try { | |
// return CryptoJS.AES.decrypt(data, CryptoJS.enc.Utf8.parse("NdRgUkXp2s5v8y/A"), { | |
// mode: CryptoJS.mode.ECB, | |
// padding: CryptoJS.pad.Pkcs7 | |
// }).toString(CryptoJS.enc.Utf8) | |
// } catch { | |
// return null | |
// } | |
// } | |
// const wssauthenticate = (req, callback) => { | |
// const query = url.parse(req.url, true).query; | |
// const device = decrypt(query.device) | |
// const token = decrypt(query.token) | |
// const pos = query.pos | |
// const client = { token, device, pos } | |
// console.log('wssauthenticate', client) | |
// if (client.token !== 'AUTH4ECR2PAYABLE') { | |
// callback(null, 401) | |
// } else if (Array.from(wss.clients).findIndex(ws => ws.data.pos === client.pos && ws.data.device === client.device && ws.data.token === client.token) > -1) { | |
// callback(null, 429) | |
// } else { | |
// callback(client) | |
// } | |
// } | |
// const ping = setInterval(() => { | |
// console.log('ping-clients', wss.clients.size) | |
// wss.clients.forEach((ws) => { | |
// if (ws.isAlive === false) return ws.terminate() | |
// ws.isAlive = false | |
// ws.ping(() => { }) | |
// }) | |
// }, 10000) | |
// server.on('upgrade', (req, socket, head) => { | |
// console.log('upgrade', socket.remoteAddress, req.url) | |
// wssauthenticate(req, (client, error) => { | |
// if (error || !client) { | |
// let headers = 'HTTP/1.1 401 Unauthorized\r\n' | |
// if (error === 429) headers = 'HTTP/1.1 429 Too Many Requests\r\n' | |
// headers += 'Connection: close\r\n' | |
// socket.write(headers + '\r\n') | |
// socket.destroy() | |
// } else { | |
// wss.handleUpgrade(req, socket, head, (ws) => { | |
// ws.data = client | |
// ws.isAlive = true; | |
// ws.on('pong', () => { | |
// console.log('pong-from', JSON.stringify(ws.data)) | |
// ws.isAlive = true | |
// }) | |
// wss.emit('connection', ws, req) | |
// }) | |
// } | |
// }) | |
// }) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment