NodeJS + WS access currently running WS server instance - node.js

I have implemented a simple REST API using NodeJS, ExpressJS and routing-controllers. I have also implemented a basic WebSocket server running alongside the REST API and using WS.
const app = express();
app.use(bodyParser.json({limit: "50mb"}));
app.use(bodyParser.urlencoded({limit: "50mb", extended: true}));
useExpressServer(app, {
controllers: [
UserController
]
});
const server = app.listen(21443, (err: Error) => {
console.log("listening on port 21443");
});
const wss = new WebSocket.Server({server});
wss.on("connection", (ws: WebSocket) => {
ws.on("message", (message: string) => {
console.log("received: %s", message);
ws.send(`Hello, you sent -> ${message}`);
});
ws.send("Hi there, I am a WebSocket server");
});
My question is how to I get access to the currently running WS instance so that I am able to send or broadcast from my controller methods. I have a number of POST methods that run long processes and so return a HTTP 200 to the client, I then would like to either send or broadcast to all connected WS clients.
What is the correct way to access the WebSocket.Server instance from within my controller classes?

You can create the websocket earlier and pass the instance around:
const notifier = new NotifierService();
notifier.connect(http.createServer(app));
app.get("/somethingHappened", () => {
notifier.broadcast("new notification!!");
});
app.use(routes(notifier))
Full code:
app.js
Pass the websocket to the other routes:
const express = require("express");
const http = require("http");
const NotifierService = require("../server/NotifierService.js");
const routes = require("./routes");
const app = express();
const server = http.createServer(app);
const notifier = new NotifierService();
notifier.connect(server);
app.get("/somethingHappened", () => {
notifier.broadcast("new notification!!");
});
// to demonstrate how the notifier instance can be
// passed around to different routes
app.use(routes(notifier));
server
.listen(4000)
.on("listening", () =>
console.log("info", `HTTP server listening on port 4000`)
);
NotifierService.js class that handles the websocket
const url = require("url");
const { Server } = require("ws");
class NotifierService {
constructor() {
this.connections = new Map();
}
connect(server) {
this.server = new Server({ noServer: true });
this.interval = setInterval(this.checkAll.bind(this), 10000);
this.server.on("close", this.close.bind(this));
this.server.on("connection", this.add.bind(this));
server.on("upgrade", (request, socket, head) => {
console.log("ws upgrade");
const id = url.parse(request.url, true).query.storeId;
if (id) {
this.server.handleUpgrade(request, socket, head, (ws) =>
this.server.emit("connection", id, ws)
);
} else {
socket.destroy();
}
});
}
add(id, socket) {
console.log("ws add");
socket.isAlive = true;
socket.on("pong", () => (socket.isAlive = true));
socket.on("close", this.remove.bind(this, id));
this.connections.set(id, socket);
}
send(id, message) {
console.log("ws sending message");
const connection = this.connections.get(id);
connection.send(JSON.stringify(message));
}
broadcast(message) {
console.log("ws broadcast");
this.connections.forEach((connection) =>
connection.send(JSON.stringify(message))
);
}
isAlive(id) {
return !!this.connections.get(id);
}
checkAll() {
this.connections.forEach((connection) => {
if (!connection.isAlive) {
return connection.terminate();
}
connection.isAlive = false;
connection.ping("");
});
}
remove(id) {
this.connections.delete(id);
}
close() {
clearInterval(this.interval);
}
}
module.exports = NotifierService;
routes.js
const express = require("express");
const router = express.Router();
module.exports = (webSocketNotifier) => {
router.post("/newPurchase/:id", (req, res, next) => {
webSocketNotifier.send(req.params.id, "purchase made");
res.status(200).send();
});
return router;
};

List of connected clients are stored inside wss object. You can receive and loop through them like this:
wss.clients.forEach((client) => {
if (client.userId === current_user_id && client.readyState === WebSocket.OPEN) {
// this is the socket of your current user
}
})
Now you need to somehow identify your client. You can do it by assigning some id to this client on connection:
wss.on('connection', async (ws, req) => {
// req.url is the url that user connected with
// use a query parameter on connection, or an authorization token by which you can identify the user
// so your connection url will look like
// http://example.com/socket?token=your_token
ws.userId = your_user_identifier
....
})
To broadcast use:
wss.clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(data);
}
});
If your controller and socket will be in different files (and I am sure they will), you will have to export the wss object in your socket file and import it in controller.

Related

Electron security (is my code is enough?)

I know about #reZach's answer about the electron security, and I know about his electron secured template.. I tried to use it, but it's just too much for today's me, I don't know anything about webpack, I know react not completely etc, the overall complexity of the template is too much for the current me. So I wanted to ask (maybe my code is good enough to be secured and safe?). I made a trading app, so I cannot give it to people not being sure that it is safe to use. I used just vanilla JS, express, localtunnel for receiving webhooks, and several modules. In short here's the code:
main.js
const { app, BrowserWindow, ipcMain } = require('electron');
const fs = require('fs');
const path = require('path');
const Store = require('electron-store');
const store = new Store();
const CryptoJS = require('crypto-js');
const axios = require('axios');
const WebSocket = require('ws');
const express = require('express');
const bodyParser = require('body-parser');
const localtunnel = require('localtunnel');
(async () => {
const tunnel = await localtunnel({ port: 3000, subdomain: 'mysubdomain' });
// the assigned public url for your tunnel
// i.e. https://abcdefgjhij.localtunnel.me
console.log(tunnel.url);
tunnel.on('close', () => {
// tunnels are closed
console.log('connection closed');
});
})();
const server = express();
const PORT = 3000;
let webhookMsg;
server.use(bodyParser.text());
server.listen(PORT, () => console.log(`Server running on port ${PORT}`));
server.get('/', function (req, res) {
res.send('Server is ready!');
});
server.post('/', (req, res) => {
webhookMsg = req.body;
res.sendStatus(200);
});
let win;
async function createWindow() {
// Create the browser window.
win = new BrowserWindow({
width: 500,
height: 550,
titleBarStyle: 'hidden',
webPreferences: {
nodeIntegration: false, // is default value after Electron v5
contextIsolation: true, // protect against prototype pollution
enableRemoteModule: false, // turn off remote
preload: path.join(app.getAppPath(), 'preload.js'), // use a preload script
backgroundThrottling: false,
},
});
// Load app
win.loadFile(path.join(__dirname, './index.html'));
win.setAlwaysOnTop(true, 'screen');
// win.removeMenu();
// rest of code..
}
app.on('ready', createWindow);
// NEXT IS MY APP MAIN LOGICS ON RECEIVING MESSAGES AND SENDING API REQUEST TO AN EXCHANGE PLATFORM AND GIVING BACK THE ANSWERS TO THE 'front-end script js file'
//for example
ipcMain.on('loadPrefs', () => {
const allPrefs = store.get('prefs');
win.webContents.send('prefs', allPrefs);
});
ipcMain.on('giveBalance', async e => {
const [apiKey, secret] = fs.readFileSync('api.txt').toString('UTF8').replace(/\r/g, '').split('\n');
const timestamp = Date.now().toString();
const params = {
api_key: apiKey,
timestamp: timestamp,
};
let orderedParams = '';
Object.keys(params)
.sort()
.forEach(function (key) {
orderedParams += key + '=' + params[key] + '&';
});
orderedParams = orderedParams.substring(0, orderedParams.length - 1);
var hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, secret);
hmac.update(orderedParams);
const sign = hmac.finalize().toString(CryptoJS.enc.Hex);
try {
const res = await axios.get(`https://api.bybit.com/v2/private/wallet/balance?&api_key=${apiKey}&sign=${sign}&timestamp=${timestamp}`);
// console.log(res.data);
const responseObj = res.data.result.USDT.equity;
win.webContents.send('balance', { responseObj });
} catch (error) {
// console.log(error);
}
});
preload.js
const { contextBridge, ipcRenderer } = require('electron');
// Expose protected methods that allow the renderer process to use
// the ipcRenderer without exposing the entire object
contextBridge.exposeInMainWorld('api', {
send: (channel, data) => {
ipcRenderer.removeAllListeners(channel);
let validChannels = [
// myChannelsList
];
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, data);
}
},
receive: (channel, func) => {
ipcRenderer.removeAllListeners(channel);
let validChannels = [
// myResponseChannelsList
];
if (validChannels.includes(channel)) {
// Deliberately strip event as it includes `sender`
ipcRenderer.on(channel, (event, ...args) => func(...args));
}
},
});
In short, I just copied this reZach's example from this answer and added my JS logics to it.
Could you please tell is it secured and safe to use, I just worry that somebody can get the user's api keys for example and take their money away:) Thank you

HTTPS over WebSockets tunnel

I'm trying to build a system in which the backend can send request to the client that will behave as a proxy. I'm constrained in using WebSockets due to the current state of the remote server. I've build a basic version of my idea that works with HTTP request sent from a browser, but as soon as I activate HTTPS it apparently fails on the handshake. I'm adding a request ID to organise and imitate the request/response model. I want to achieve an E2E encryption with this proxy chain.
This is my code for the proxy that catches the requests and sends them over the WebSocket:
const net = require('net');
const WebSocket = require('ws');
const crypto = require("crypto");
const wss = new WebSocket('ws://localhost:8001');
const server = net.createServer();
server.on('connection', (socket) => {
// settings per connection opened
let requests = [];
// Receives data
socket.on('data', data => {
const requestID = crypto.randomBytes(16).toString("hex");
const additionalInfo = JSON.stringify({
"Request": requestID,
});
const header = Buffer.from(`${additionalInfo.length} ${additionalInfo}\n\n`);
wss.send(Buffer.concat([header, data]));
requests.push(requestID);
});
socket.on('error', error => {
console.log(error);
});
socket.on('end', () => {
requests = [];
});
// server response to the request
wss.on('message', (data) => {
// extract basic data
const jsonDataSize = data.toString().split(' ')[0];
const jsonDataOffset = jsonDataSize.length + 1;
const jsonDataText = data.slice(jsonDataOffset, Number(jsonDataSize) + jsonDataOffset).toString();
const jsonData = JSON.parse(jsonDataText);
const message = data.slice(Number(jsonDataSize) + jsonDataOffset + 2);
// check if received response matches the request
if (requests.includes(jsonData.Request)) {
// console.log(data.toString());
socket.write(message);
}
});
wss.on('error', error => {
console.log(error);
});
});
server.on('close', () => {
console.log("Server closed");
})
server.listen({host: "localhost", port: 8000}, () => {
console.log("Server listening on localhost:8000");
});
This is my code for the WebSocket receiver:
const net = require('net');
const WebSocket = require('ws');
const wss = new WebSocket.Server({port: 8001}, () => {
console.log('WebSocket server listening on localhost:8001');
});
wss.on('connection', socket => {
let server;
// trigger for a new message from the same connection
socket.on('message', data => {
// console.log("---------->");
// console.log(data.toString());
const jsonDataSize = data.toString().split(' ')[0];
const jsonDataOffset = jsonDataSize.length + 1;
const jsonDataText = data.slice(jsonDataOffset, Number(jsonDataSize) + jsonDataOffset).toString();
// check if it is a new tls connection request
let isTLSConnection = data.toString().indexOf("CONNECT") !== -1;
// set the new connection's settings
if (isTLSConnection && data.toString().includes('Host: ')) {
const serverPort = 443;
const serverAddress = data
.toString()
.split("CONNECT")[1]
.split(" ")[1]
.split(":")[0];
server = net.createConnection({host: serverAddress, port: serverPort});
// Send back 200 OK to the browser
const header = Buffer.from(`${jsonDataSize} ${jsonDataText}\n\n`);
socket.send(Buffer.concat([header, Buffer.from("HTTP/1.1 200 OK\r\n\r\n")]));
return;
} else if (data.toString().includes('Host: ')) {
const serverPort = 80;
const serverAddress = data.toString().split('Host: ')[1].split("\r\n")[0];
server = net.createConnection({host: serverAddress, port: serverPort});
}
// extract payload
const message = data.slice(Number(jsonDataSize) + jsonDataOffset + 2);
// send payload to server
server.write(message);
server.on('data', (data) => {
// console.log("<----------");
// console.log(data.toString());
const header = Buffer.from(`${jsonDataSize} ${jsonDataText}\n\n`);
socket.send(Buffer.concat([header, data]));
});
server.on('error', error => {
console.log(error);
});
});
socket.on('error', (error) => {
console.log(error);
});
});
I took inspiration from Build your own proxy server from scratch
I tried implementing a request/response model on top of WebSockets since I believe the error relies there, but it didn't work
You should use wss://localhost:8001 when using https

App Engine can't find default credentials to connect to Firestore in Google Cloud

I have a NextJS Typescript app running on Google App Engine. It fetches data from Firestore and everything works fine. In order to improve the speed of the app I'm experimenting new data fetching infrastructure in which the server listens to Firestore collections and updates all the data to JSON files in the tmp folder when changes are made in Firestore. This way all the data is up-to-date and available to the App Engine all the time. Locally this works like a charm.
There are some obvious things I need to improve, but the next step for me is to run a dev project in GCP and see if my memory usage is ok and if it works as quickly as I hope etc. But the problem is that when I change my NextJS infra to include a custom server, the connection between App Engine and Firestore vanishes.
The problem I'm seeing on GCP logs is:
Error: Could not load the default credentials. Browse to https://cloud.google.com/docs/authentication/getting-started for more information.
at GoogleAuth.getApplicationDefaultAsync (/workspace/node_modules/google-auth-library/build/src/auth/googleauth.js:180:19)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at runNextTicks (node:internal/process/task_queues:65:3)
at listOnTimeout (node:internal/timers:526:9)
at processTimers (node:internal/timers:500:7)
at async GoogleAuth.getClient (/workspace/node_modules/google-auth-library/build/src/auth/googleauth.js:558:17)
at async GrpcClient._getCredentials (/workspace/node_modules/google-gax/build/src/grpc.js:145:24)
at async GrpcClient.createStub (/workspace/node_modules/google-gax/build/src/grpc.js:308:23)
The actual error message in the client is "502 Bad Gateway – nginx".
Earlier I had a basic NextJS app which has frontend pages and backend API routes. The routes connect to Firestore and serve that data to correct users etc. The main difference is that I've added a custom server that initiates the listeners:
import { Firestore } from '#google-cloud/firestore';
import express, { Request, Response } from 'express';
import next from 'next';
import fs from 'fs';
import os from 'os';
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
const port = process.env.PORT || 3000;
let firestoreListeners: { [collectionId: string]: () => void } = {};
const unsubscribeAllListeners = () => {
for (const collectionId of Object.keys(firestoreListeners)) {
console.log('unsubscribing from', collectionId);
firestoreListeners[collectionId]();
}
firestoreListeners = {};
};
const skippedCollections = ['analytics', 'pageRevisions', 'newsItemRevisions'];
app.prepare().then(() => {
const server = express();
unsubscribeAllListeners();
const firestoreSettings = {} as FirebaseFirestore.Settings;
if (process.env.GCP_KEYFILE_NAME) {
firestoreSettings.keyFilename = process.env.GCP_KEYFILE_NAME;
}
const firestoreData: {
[collectionId: string]: {
[id: string]: any;
};
} = {};
const firestore = new Firestore(firestoreSettings);
firestore.listCollections().then((collections) => {
for (const collection of collections) {
if (
!firestoreListeners[collection.id] &&
!skippedCollections.includes(collection.id)
) {
console.log('listening to', collection.id);
firestoreData[collection.id] = {};
const listener = firestore
.collection(collection.id)
.onSnapshot((snapshot) => {
firestoreData[collection.id] = {};
for (const doc of snapshot.docs) {
firestoreData[collection.id][doc.id] = {
_id: doc.id,
...doc.data(),
};
}
if (!fs.existsSync(os.tmpdir() + '/data')) {
fs.mkdirSync(os.tmpdir() + '/data');
}
fs.writeFileSync(
os.tmpdir() + `/data/${collection.id}.json`,
JSON.stringify(firestoreData[collection.id])
);
console.log(
'updated',
collection.id,
'with',
snapshot.docs.length,
'docs'
);
});
firestoreListeners[collection.id] = listener;
}
}
});
server.all('*', (req: Request, res: Response) => {
return handle(req, res);
});
server.listen(port, (err?: any) => {
if (err) throw err;
console.log(
`> Ready on localhost:${port} - env ${process.env.NODE_ENV}`
);
});
server.on('close', function () {
unsubscribeAllListeners();
});
process.on('beforeExit', () => {
unsubscribeAllListeners();
});
});
The build and deploy scripts are ok, it works if I take the listener logic out of the equation and just deploy the custom server.
What's the problem? Is it some nginx problem or do I have something else off?
The problem apparently is that I cannot initiate my Firestore connection before listen or even at the listen callback. I have to do it a bit later (to give GAE a possibility to authenticate for Firestore?).
When I moved my listeners to listen to all endpoints, it worked. Below is a solution that helped with the problem. I don't feel it's that beautiful, but gets the job done.
import { Firestore } from '#google-cloud/firestore';
import express, { Request, Response } from 'express';
import next from 'next';
import fs from 'fs';
import os from 'os';
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
const port = process.env.PORT || 3000;
let firestoreListeners: { [collectionId: string]: () => void } = {};
const unsubscribeAllListeners = () => {
for (const collectionId of Object.keys(firestoreListeners)) {
console.log('unsubscribing from', collectionId);
firestoreListeners[collectionId]();
}
firestoreListeners = {};
};
const skippedCollections = ['analytics', 'pageRevisions', 'newsItemRevisions'];
export const firestoreData: {
[collectionId: string]: {
[id: string]: any;
};
} = {};
let listenersInitiated = false;
const initiateListeners = () => {
if (listenersInitiated) {
return;
}
const firestoreSettings = {} as FirebaseFirestore.Settings;
if (process.env.GCP_KEYFILE_NAME) {
firestoreSettings.keyFilename = process.env.GCP_KEYFILE_NAME;
}
const firestore = new Firestore(firestoreSettings);
firestore.listCollections().then((collections) => {
for (const collection of collections) {
if (
!firestoreListeners[collection.id] &&
!skippedCollections.includes(collection.id)
) {
console.log('listening to', collection.id);
firestoreData[collection.id] = {};
const listener = firestore
.collection(collection.id)
.onSnapshot((snapshot) => {
firestoreData[collection.id] = {};
for (const doc of snapshot.docs) {
firestoreData[collection.id][doc.id] = {
_id: doc.id,
...doc.data(),
};
}
if (!fs.existsSync(os.tmpdir() + '/data')) {
fs.mkdirSync(os.tmpdir() + '/data');
}
fs.writeFileSync(
os.tmpdir() + `/data/${collection.id}.json`,
JSON.stringify(firestoreData[collection.id])
);
console.log(
'updated',
collection.id,
'with',
snapshot.docs.length,
'docs'
);
});
firestoreListeners[collection.id] = listener;
}
}
});
listenersInitiated = true;
};
app.prepare().then(() => {
const server = express();
unsubscribeAllListeners();
server.all('*', (req: Request, res: Response) => {
initiateListeners();
return handle(req, res);
});
server.listen(port, (err?: any) => {
if (err) throw err;
console.log(
`> Ready on localhost:${port} - env ${process.env.NODE_ENV}`
);
});
server.on('close', function () {
console.log('Closing');
unsubscribeAllListeners();
});
process.on('beforeExit', () => {
console.log('Closing');
unsubscribeAllListeners();
});
});
According to my initial tests this works very nicely in GAE. When setting the app.yaml settings correctly, it provides nice speed with low costs.
This does not really handle listeners failing if a server instance lives for a long time and also, it might initiate too many listeners, but the initial results of my tests are promising!

Node js Socket.iO accessing socket outside for multiple client

How can we access socket object outside for multiple socket connection. I created a object globally and tried to do this. But it always works for last connected socket.
'use strict';
const path = require('path')
const express = require('express');
const http = require('http');
const chalk = require('chalk');
const socketio = require('socket.io');
var connectionString = '';
const eventHubConsumerGroup = ""
const app = express()
const server = http.createServer(app ,() => {
console.log(chalk.green('Server created'))
})
const io = socketio(server)
const port = process.env.port || 3000
const publicDirectoryPath = path.join(__dirname , '../public')
var server_token = "1234567890";
app.use(express.static(publicDirectoryPath))
var localSocket;
io.on('connection',function(socket){
localSocket = socket;
console.log(socket.handshake.query.deviceID)
console.log('on user connected '+socket.id);
//report = new Report(socket);
socket.auth = false;
socket.on('authenticate',function(token){
console.log('token recieved is '+token);
if(server_token == token){
socket.auth = true;
console.log('connection is authenticated '+socket.id);
socket.emit("authenticate",true);
} else {
console.log("Connection not established")
socket.emit("authenticate",false);
}
})
socket.on('sendSocketEvent' , message => {
console.log(chalk.yellowBright(`Message recieved from ${socket.id} + ${message}`));
io.to(socket.id).emit('recieveSocketEvent', `Hello test`);
})
socket.on('disconnect',function(){
console.log('one user disconnected '+socket.id);
})
setTimeout(function(){
if(!socket.auth){
console.log('disconnecting the socket '+socket.id);
socket.emit("timeOut");
socket.disconnect();
}
},1000);
})
server.listen(port,() => {
console.log(chalk.redBright(`Server is up on port ${port}`))
})
var printMessage = function (message) {
console.log(JSON.stringify(message));
console.log(message.DeviceId);
if (localSocket != null){
if (message.DeviceId == localSocket.handshake.query.deviceID) {
localSocket.emit('recieveSocketEvent', message);
}
}
};
class EventHubReader {
constructor(connectionString, consumerGroup) {
this.connectionString = connectionString;
this.consumerGroup = consumerGroup;
this.eventHubClient = undefined;
this.receiveHandlers = undefined;
}
async startReadMessage(startReadMessageCallback) {
try {
console.log(this.connectionString)
const client = await EventHubClient.createFromIotHubConnectionString(this.connectionString);
console.log('Successfully created the EventHub Client from IoT Hub connection string.');
this.eventHubClient = client;
const partitionIds = await this.eventHubClient.getPartitionIds();
console.log('The partition ids are: ', partitionIds);
const onError = (err) => {
console.error(err.message || err);
};
const onMessage = (message) => {
const deviceId = message.annotations['iothub-connection-device-id'];
return startReadMessageCallback(message.body, message.enqueuedTimeUtc, deviceId);
};
this.receiveHandlers = partitionIds.map(id => this.eventHubClient.receive(id, onMessage, onError, {
eventPosition: EventPosition.fromEnqueuedTime(Date.now()),
consumerGroup: this.consumerGroup,
}));
} catch (ex) {
console.error(ex.message || ex);
}
}
// Close connection to Event Hub.
async stopReadMessage() {
const disposeHandlers = [];
this.receiveHandlers.forEach((receiveHandler) => {
disposeHandlers.push(receiveHandler.stop());
});
await Promise.all(disposeHandlers);
this.eventHubClient.close();
}
}
var { EventHubClient, EventPosition } = require('#azure/event-hubs');
const eventHubReader = new EventHubReader(connectionString, eventHubConsumerGroup);
(async () => {
console.log("Step1")
await eventHubReader.startReadMessage((message, date, deviceId) => {
console.log("Here getting called");
try {
const payload = {
IotData: message,
MessageDate: date || Date.now().toISOString(),
DeviceId: deviceId,
};
printMessage(payload);
} catch (err) {
console.error('Error broadcasting: [%s] from [%s].', err, message);
}
});
})().catch();
the problem is in condition "printMessage" . here I am trying to restrict the emit based on socket deviceID, but it's only working for last connected socket.
Can You please help me in this.
var localSocket;
io.on('connection',function(socket){
localSocket = socket;
})
You're overwriting the same variable, on each new connection, which means it will always point to the last socket connected.
What exactly do you want to do? To send this message to all connected sockets?

nodejs express server stops unexpectedly

I have a server built with express and socket IO. The problem is that every time the server just stops responding 2 minutes after first client connection. Things I have already done/checked:
Express logs show no errors.
socket.IO logs show no errors on server side.
socket.IO logs show ping timeout on client side (after a few successful pings).
Listening to the uncaughtException/UnhandeledRejection doesn't help.
So, when I start the server, and GET /login through the browser, without doing anything else, the server will stop responding on its own after ~2 minutes, and the only way to close it is closing the cmd (CTRL+C doesn't work even after listening to SIGINT).
I'll post the relevant parts of the code here:
server.js
const http = require('http');
const express = require('express');
const socketIO = require('socket.io');
let app = express();
let server = http.createServer(app);
var io = socketIO(server);
app.get(`/login`, (req, res) => {
console.log(`got GET /login`);
res.sendFile(publicPath + '/login.html');
});
io.on(`connection`, (socket) => {
socket.on(`login`, async (details, cb) => {
login(details.username, details.password, async (res) => {
if (res === true) {
let user = new User(details.username, details.password);
let token = await user.generateAuthToken();
cb(`/set?token=${token}`);
} else if (res === false) {
socket.emit(`loginFailed`, 'Password incorrect. Please try again!')
} else if (res === `Username doesn't exist`) {
socket.emit(`loginFailed`, res)
}
});
});
socket.on('getAllLeads', async (callback) => {
leads = await getAllLeads();
callback(leads);
});
socket.on('getSomeLeads', async (options, callback) => {
leads = await getSomeLeads(options);
callback(leads);
});
socket.on(`newFile`, ({text, words, options, fileName}) => {
console.log('Starting...');
words.forEach((wordSet, index) => {
wordSet.forEach(word => {
regexp = `\\s+${word}+\\s`;
re = new RegExp(regexp);
text = text.replace(re, `${options[index]}`);
});
});
fs.writeFileSync(`${fileName}.txt`, text, 'utf8');
console.log(`Finished writing to ${fileName}.txt successfully!`);
});
});
server.listen(3000, () => {
console.log(chalk.yellow(`Server is up on port ${port}`));
});
login.js
const socket = io();
socket.on(`reconnect_error`, (err) => {
console.log(err);
});
socket.on(`connect`, () => {
console.log('connected to login page');
if (getQueryVariable('failed')) {
$('.error, .error p').css('opacity', 1);
$('.error p').text('Unauthorized! PLEASE log in.');
}
socket.on(`loginFailed`, (reason) => {
$('.error, .error p').css('opacity', 1);
$('.error p').text(reason);
console.log(`got login failed`);
});
$('#form').submit((e) => {
e.preventDefault();
let username = $('#username').val();
let password = $('#pass').val();
socket.emit(`login`, {username, password}, (path) => {
window.location.href = path;
});
});
});
function getQueryVariable(variable)
{
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
if (pair[0] == variable) return pair[1];
}
return (false);
}

Resources