I want to add an anti-spam function in my socket.io chatroom using the socket-anti-spam module but I have no clue how to. I've tried a couple stuff, but they didn't seem to work.
If you can't help with the socket-anti-spam module, any other module is fine aswell. This version of my server.js has the anti-spam setup but it doesn't seem to work.
If you need any other information (which I doubt you'll need) like HTML or CSS, just comment and I'll update this question.
My server.js:
var PORT = process.env.PORT || 3000;
var express = require("express");
var app = express();
var http = require("http").Server(app);
var io = require("socket.io")(http);
var moment = require("moment");
var connectedUsers = {};
var prefix = "^";
var sysusername = "Twintails🎀";
function sleep(ms) {
var unixtime_ms = new Date().getTime();
while (new Date().getTime() < unixtime_ms + ms) {}
}
const SocketAntiSpam = require('socket-anti-spam')
const socketio = require('socket.io').listen(8080)
const socketAntiSpam = new SocketAntiSpam({
banTime: 30, // Ban time in minutes
kickThreshold: 2, // User gets kicked after this many spam score
kickTimesBeforeBan: 1, // User gets banned after this many kicks
banning: true, // Uses temp IP banning after kickTimesBeforeBan
io: socketio, // Bind the socket.io variable
})
app.use(express.static(__dirname + "/public"));
io.on("connection", function(socket) {
socketAntiSpam.event.on('ban', data => {
socket.emit("message", {
username: sysusername,
text: "A user was banned...",
timestamp: moment().valueOf()
});
})
console.log("A user is connected.");
socket.on("disconnect", function() {
var userData = connectedUsers[socket.id];
if (typeof userData !== "undefined") {
socket.leave(connectedUsers[socket.id]);
io.to(userData.room).emit("message", {
username: sysusername,
text: userData.username + " has left!",
timestamp: moment().valueOf()
});
delete connectedUsers[socket.id];
}
});
socket.on("joinRoom", function(req, callback) {
if (req.username.replace(/\s/g, "") !== "Twintails🎀") {
if (req.username.replace(/\s/g, "").length < 24) {
if (
req.room.replace(/\s/g, "").length > 0 &&
req.username.replace(/\s/g, "").length > 0
) {
var nameTaken = false;
Object.keys(connectedUsers).forEach(function(socketId) {
var userInfo = connectedUsers[socketId];
if (
userInfo.username.toUpperCase() === req.username.toUpperCase()
) {
nameTaken = true;
}
});
if (nameTaken) {
callback({
nameAvailable: false,
error: "This username is taken, please choose another one."
});
} else {
connectedUsers[socket.id] = req;
socket.join(req.room);
socket.broadcast.to(req.room).emit("message", {
username: sysusername,
text: req.username + " has joined!",
timestamp: moment().valueOf()
});
callback({
nameAvailable: true
});
}
} else {
callback({
nameAvailable: false,
error: "Please complete the forum."
});
}
} else {
callback({
nameAvailable: false,
error: "Please make a username less than 24 characters."
});
}
} else {
callback({
nameAvailable: false,
error: "Your username can't be: " + sysusername
});
}
});
socket.on("message", function(message, callback, req) {
if (message.text.length > null) {
if (message.text !== " ") {
if (message.text !== " ") {
if (message.text !== " ") {
if (message.text !== " ") {
if (message.text !== " ") {
if (message.text !== " ") {
if (message.text !== " ") {
if (message.text !== " ") {
if (message.text !== " ") {
if (message.text.length < 200) {
message.timestamp = moment().valueOf();
io.to(connectedUsers[socket.id].room).emit(
"message",
message
);
}
}
}
}
}
}
}
}
}
}
}
});
socket.emit("message", {
username: sysusername,
text: "Ask someone to join this chat room to start talking.",
timestamp: moment().valueOf()
});
socket.on("message", function(message) {
if (message.text === prefix + "discord") {
socket.emit("message", {
username: sysusername,
text: "Join the Twintails🎀 server here: https://discord.gg/fK9ynNq",
timestamp: moment().valueOf()
});
sleep(1000);
}
});
socket.on("message", function(message) {
if (message.text === prefix + "bot") {
socket.emit("message", {
username: sysusername,
text: "Coming soon...",
timestamp: moment().valueOf()
});
sleep(1000);
}
});
});
http.listen(PORT, function() {
console.log("Server started on port " + PORT);
});
Thanks!
you can store the messages that the user sends and prevent if the current message is like the previous one
Related
have a strange thing happening running a Google cloud function. The function starts and logs the user id and job id as expected. Then it calls firestore db and basically sits there for 1 minute, sometimes 2 before it executes the first call... It was even timing out on 240 seconds.
const AWS = require('aws-sdk');
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.run = functions.https.onCall((data, context) => {
var id = data.id;
var userid = data.uid;
var retry = data.retry;
var project;
var db = admin.firestore();
var storage = admin.storage();
console.log("Starting Collect");
console.log("UID: " + userid);
console.log("id ID: " + id);
// Times out on this call
db.collection("users").doc(userid).collection("ids").doc(id).get().then(function(doc) {
console.log("Loaded DB");
project = doc.data();
createexport();
}).catch(function(err) {
console.log(err);
error('Loading DB Error, ' + err, false);
});
function createexport() {
db.collection("exports").doc(id).set({
status: 'Collecting',
stage: 'Export Checker',
percent: 0,
id: id,
}).then(function() {
console.log("Creating Export");
setdb();
}).catch(function(err) {
error("Error creating export in database :" + err, true)
});
}
function setdb() {
db.collection("users").doc(userid).collection("ids").doc(id).update({
status: 'Analyzing Files',
stage: 'Collecting'
}).then(function() {
getaudio();
}).catch(function(err) {
error("Error updating users id in database :" + err, true)
});
}
function getaudio() {
const from = userid + '/projects/' + project.originalproject.id + '/audio.' + project.originalproject.extension;
const to = userid + '/' + id + '/audio.' + project.originalproject.extension;
storage.bucket('---------').file(from).copy(storage.bucket('---------').file(to)).then(function() {
console.log("Collecting files");
copy2();
}).catch(function(err) {
error('Collecting Audio Error, ' + err, true);
});
}
function copy2() {
const from = userid + '/projects/' + project.originalproject.id + '/overlay.png';
const to = userid + '/' + id + '/overlay.png';
storage.bucket('--------.appspot.com').file(from).copy(storage.bucket('---------').file(to)).then(function() {
updateexport();
}).catch(function(err) {
error('Collecting Overlay Error, ' + err, true);
});
}
function updateexport() {
db.collection("exports").doc(id).update({ status: "Waiting" }).then(function() {
console.log("All files collected");
return { status: 'Success' };
}).catch(function(err) {
error("Error creating export entry in database :" + err, true)
});
}
function error(evt, evt2) {
AWS.config.update({ region: "us-east-1" });
var html;
var sub = 'Error with id ' + id;
console.log(evt);
if (evt2) {
db.collection('users').doc(userid).collection('ids').doc(id).update({
status: 'Error'
}).catch(function(err) {
console.log(err);
});
db.collection("exports").doc(id).update({
status: 'Error',
stage: 'Collecting',
error: evt,
}).catch(function(err) {
console.log(err);
});
html = `
Username: ${project.username} <br>
UserID: ${userid} <br>
Email: ${project.email} <br>
id: ${id}
`
} else {
html = `id: ${id}<br>
UserID: ${userid} <br>
Message: Error logged was: ${evt}
`
}
var params = {
Destination: {
ToAddresses: [
'errors#mail.com'
]
},
Message: {
Body: {
Html: {
Charset: "UTF-8",
Data: html
},
},
Subject: {
Charset: 'UTF-8',
Data: sub
}
},
Source: 'errors#mail.com',
ReplyToAddresses: [
project.email
],
};
var sendPromise = new AWS.SES({
apiVersion: "2010-12-01",
"accessKeyId": "-----------",
"secretAccessKey": "------------------------",
"region": "--------",
}).sendEmail(params).promise();
sendPromise.then(function(data) {
return { data: data };
}).catch(function(err) {
return { err: err };
});
}
});
Seems to me to be way too long for a database call of only a few kb. I will attach the cloud log to show time difference. After this initial slump it then performs as expected.
Cloud log image
Anyone got any ideas as to why this could be happening? Many thanks...
Your function is appearing to hang because it isn't handling promises correctly. Also, it doesn't appear to be sending a specific response to the client app. The main point of callable functions is to send a response.
I suggest reviewing the documentation, where you will learn that callable functions are required to return a promise that resolves with an object to send to the client app, after all the async work is complete.
Minimally, it will take a form like this:
return db.collection("users").doc(userid).collection("files").doc(id).get().then(function(doc) {
console.log("Loaded DB");
project = doc.data();
return { "data": "to send to the client" };
}
Note that the promise chain is being returned, and the promise itself resolves to an object to send to the client.
Trying to SSH to a server and able to. However, when I try to run sudo command it prompts me to enter the password of the userid mentioned. How do I prevent any keyboard interruption and hardcode the password so it doesn't prompt for password.
server.js
const { Client } = require('ssh2');
const conn = new Client();
conn.on('ready', () => {
console.log('Client :: ready');
conn.exec('sudo ls -lrt',{ stdin: 'password\n', pty: true }, (err, stream) => {
if (err) throw err;
stream.on('close', (code, signal) => {
console.log('Stream :: close :: code: ' + code + ', signal: ' + signal);
conn.end();
}).on('data', (data) => {
console.log('STDOUT: ' + data);
}).stderr.on('data', (data) => {
console.log('STDERR: ' + data);
});
});
}).connect({
host: 'hostname',
port: 22,
username: 'user1',
password: 'password'
});
The prompt I get:
STDOUT: [sudo] password for user1:
STDOUT:
sudo: timed out reading password
The below code works for me.
const Client = require('ssh2').Client;
const conn = new Client();
const encode = 'utf8';
const connection = {
host: 'hostname.foo.com',
username: 'iamgroot',
password: 'root#1234'
}
conn.on('ready', function() {
// Avoid the use of console.log due to it adds a new line at the end of
// the message
process.stdout.write('Connection has been established');
let password = 'root#1234';
let command = '';
let pwSent = false;
let su = false;
let commands = [
`ls -lrt`,
`sudo su - root`,
`ls -lrt`
];
conn.shell((err, stream) => {
if (err) {
console.log(err);
}
stream.on('exit', function (code) {
process.stdout.write('Connection closed');
conn.end();
});
stream.on('data', function(data) {
process.stdout.write(data.toString(encode));
// Handles sudo su - root password prompt
if (command.indexOf('sudo su - root') !== -1 && !pwSent) {
if (command.indexOf('sudo su - root') > -1) {
su = true;
}
if (data.indexOf(':') >= data.length - 2) {
pwSent = true;
stream.write(password + '\n');
}
} else {
// Detect the right condition to send the next command
let dataLength = data.length > 2;
let commonCommand = data.indexOf('$') >= data.length - 2;
let suCommand = data.indexOf('#') >= data.length - 2;
console.log(dataLength);
console.log(commonCommand);
console.log(suCommand);
if (dataLength && (commonCommand || suCommand )) {
if (commands.length > 0) {
command = commands.shift();
stream.write(command + '\n');
} else {
// su requires two exit commands to close the session
if (su) {
su = false;
stream.write('exit\n');
} else {
stream.end('exit\n');
}
}
}
}
});
// First command
command = commands.shift();
stream.write(command + '\n');
});
}).connect(connection);
I fetch unread messages in a middle ware that triggers my function every five minutes. It is successfully completing the request but eventually It triggers and crashes my nodejs process. With an error of:
Error: This socket has been ended by the other party
I have tried adding all these catches and error handling but It seams it eventually times out my connection to my inbox? Am I not reconnecting on every request to access my inbox?
Here is my code (also I have tried with authTimeout: 3000 in the config before anyone suggests that is the issue):
imap: {
user: 'myemail#gmail.com',
password: 'myPW',
host: 'imap.gmail.com',
port: 993,
tls: true,
keepalive: true
}
imaps.connect(settings.emailConfig).then(function (connection) {
return connection.openBox('INBOX').then(function () {
var searchCriteria = ['UNSEEN'];//only grab unread messages in LTS email
var fetchOptions = {
bodies: ['HEADER', 'TEXT', ''],
markSeen: true//mark as read
};
return connection.search(searchCriteria, fetchOptions).then(function (messages) {
console.log('looking for unread messages')
if (messages.length > 0) {
console.log('unread messages to save')
console.log('looking at messages : ' + util.inspect(messages, { depth: null }))
var saveUnreadEmais = messages.map(function (item) {//resolve each promise of unread message
var all = _.find(item.parts, { "which": "" })
var id = item.attributes.uid;
var idHeader = "Imap-Id: " + id + "\r\n";
simpleParser(idHeader + all.body, (err, mail) => {
var BarCode = "";
var subject = mail.subject;
var to = mail.to.value[0].address;
var from = mail.from.value[0].address;
var text = mail.text;
if (mail.subject.includes('Barcode :')) {//if the message to the system includes BarCode in the subject line grab it
var split = mail.subject.split(':');
BarCode = split[1];
}
if (!subject) {
subject = "LTS Email Recieved - Barcode : " + BarCode;
}
if (!text) {
text = "LTS auto email"
}
var newrec = {};
newrec.MessageDate = new Date();
newrec.MessageFor = to;
newrec.MessageFrom = from;
newrec.Message = text;
newrec.MessageAbout = BarCode;
newrec.MessageSubject = subject;
newrec.MessageStatusCode = 1;//1 sent, 2 read, 3 saved, -1 deleted
//console.log('saving message with details of : ' + util.inspect(newrec, { depth: null }))
return db.knex('dbo.PersonnelMessages').insert(newrec).then((data) => {
return "sent";
});
});
});
return Promise.all(saveUnreadEmais).then(() => {
//do anything you want after saving all unred emails to our db.
}).catch((err) => { console.log("error : " + err) })
}
else {
console.log('no new emails')
}
}).catch((err) => { console.log("error : " + err) })
}).catch((err) => { console.log("opening inbox error : " + err) })
}).then(function () {
console.log('In the INBOX');
}).catch(function (e) {
console.log('error : ' + e);
});
I have a bot. It can input some text and return some word.
I would like to use MongoDB. Because Heroku can't store data.
So I add function.js that use mongoose.
console.log('data.functionswitch = ' + data.functionswitch);
console log is work fine. It can reply what i want.
return data.functionswitch;
but return data.functionswitch only return undefined when i call it in input.js/.
I have try async/await.
But it only stops working.
How can I improve it and make it work? Thank you.
-
-
2018/03/15 updated
function.js
function switchfind(id, name, callback) {
mongodb.functionSwitch.findOne({
groupid: id, functionname: name
}, function (err, data) {
if (err) {
console.log(err);
callback(null);
return;
}
else if (!data) {
console.log("No record found")
callback(null);
return;
}
console.log('date = ' + data);
console.log('data.functionswitch = ' + data.functionswitch);
callback(data.functionswitch);
return;
})
};
input.js
function parseInput(rplyToken, inputStr) {
//console.log('InputStr: ' + inputStr);
_isNaN = function (obj) {
return isNaN(parseInt(obj));
}
let msgSplitor = (/\S+/ig);
let mainMsg = inputStr.match(msgSplitor);
let trigger = mainMsg[0].toString().toLowerCase();
exports.mongoose.switchfind(mainMsg[1], mainMsg[2], function (functionswitch) {
console.log('functionswitch = ' + functionswitch)
if (functionswitch === null) {
console.log('HERE === NULL ')
}
if (functionswitch == 0) {
console.log('HERE != 0')
return;
}
else if (functionswitch != 0 ) {
console.log('HERE != 0')
if (inputStr.match(/\w/) != null && inputStr.toLowerCase().match(/\d+d+\d/) != null) return exports.rollbase.nomalDiceRoller(inputStr, mainMsg[0], mainMsg[1], mainMsg[2]);
}
})
}
update
const mongoose = require('mongoose');
let uristring = process.env.mongoURL ||
'mongodb://XXXXXXX';
mongoose.connect(uristring);
mongoose.connect(uristring, function (err, res) {
if (err) {
console.log('ERROR connecting to: ' + uristring + '. ' + err);
} else {
console.log('Succeeded connected to: ' + uristring);
// console.log('allswitch: ' + allswitch);
}
});
var functionSchema = new mongoose.Schema({
groupid: String,
functionname: String,
functionswitch: String
});
// Compiles the schema into a model, opening (or creating, if
// nonexistent) the 'PowerUsers' collection in the MongoDB database
var functionSwitch = mongoose.model('functionSwitchs', functionSchema);
The problem in your code is that you are using findOne as it was synchronous. You cannot simply return the data, you have to use a callback.
Here is a tutorial about callbacks.
Example of what it should look like :
// The find function
function switchfind(id, name, callback) {
mongodb.functionSwitch.findOne({
groupid: id,
functionname: name
}, function (err, data) {
// Handle error
if (err) {
callback(null);
return;
}
// Handle empty data
if (data == null) {
callback(null);
return;
}
// Handle with data
callback(data.functionswitch);
})
};
// How to call it
funcX() {
switchfind(id, name, function (functionswitch) {
if (functionswitch === null) {
// Handle the error
}
// Handle the data
});
}
I am trying to test a constructor in node.js that uses asynchronous code, to test out a feature in it. I know the asynchronous code works because I have already ran it, before I put in the feature, as if I were an end-user. In fact, I got it thanks to some user who answered another question I had
The feature
The User constructor has a userRole member, and some async code that checks userType specified against User.userTypes. If userType found, this.userRole is set to userType. Else, exception is thrown.
The code looks like this:
async.forEachSeries(
User.userTypes,
function(user_type, callback)
{
if (user_type == userType)
{
this.userRole = user_type;
return;
}
if (user_type == User.userTypes[User.userTypes.length - 1])
{
callback(helpers.invalidData("user_role"));
return;
}
callback(null);
},
function(err)
{
if (err)
{
if (DEBUG)
{
console.log("Error from constructor...");
console.log(JSON.stringify(err, null, '\t') + "\n");
}
throw err;
}
}
);
The rest of the constructor looks like:
function User(id, email, displayName, password, userType, deleted, cb)
{
var DEBUG = true;
var error = null;
this.userID = id;
this.email = email;
this.displayName = displayName;
this.deleted = deleted;
var self = this;
async.forEachSeries(
User.userTypes,
function(user_type, callback)
{
if (user_type == userType)
{
this.userRole = user_type;
return;
}
if (user_type == User.userTypes[User.userTypes.length - 1])
{
callback(helpers.invalidData("user_role"));
return;
}
callback(null);
},
function(err)
{
if (err)
{
if (DEBUG)
{
console.log("Error from constructor...");
console.log(JSON.stringify(err, null, '\t') + "\n");
}
throw err;
}
}
);
if (User.connectedToDatabase) this._password = password;
else
{
bcrypt.genSalt(10, function (e, salt) {
bcrypt.hash(password, salt, function (e, hash) {
if (!e)
{
self._password = hash;
if (DEBUG)
{
console.log("this._password ==" + self._password);
console.log("this.userID == " + self.userID);
}
if (typeof cb === 'function')
cb(null, this);
}
else
{
console.log("Error occurred: ");
console.log(e);
if (typeof cb === 'function')
cb(e);
}
})
});
}
}
User.connectedToDatabase = false;
User.BASIC = "basic user";
User.INVENTORY_MANAGEMENT = "inventory";
User.ADMIN = "admin";
User.userTypes = [ User.BASIC, User.INVENTORY_MANAGEMENT, User.ADMIN ];
User.prototype.userID = 0;
User.prototype.email = null;
User.prototype.displayName = null;
User.prototype._password = null;
User.prototype.userRole = User.BASIC;
User.prototype.deleted = false;
User.prototype.responseObject = function() {
return {
id: this.userID,
email: this.email,
displayName: this.displayName,
userType: this.userRole
};
}
My test
I write test() function that takes parameters to pass to User. If User constructed without error, it, along with some of its members are printed to console. Else, error is printed. Here is code:
function test(email, name, pass, type)
{
try
{
var a = new User(Math.round(Math.random() * 32),
email,
name,
pass,
type
);
console.log("Test user created: " + JSON.stringify(a.responseObject(), null, '\t') + "\n");
console.log("User._password == " + a._password);
console.log("\n");
}
catch (e)
{
console.log("User could not be created.\n" + JSON.stringify(e, null, '\t') + "\n");
}
/*async.waterfall([
function(callback){
var a = new User(Math.round(Math.random * 32),
email,
name,
pass,
type);
callback(null, a);
},
function(a, callback) {
console.log("Test user created: " + JSON.stringify(a, null, '\t') + "\n");
console.log("User._password == " + a._password);
console.log("User.userID == " + a.userID);
console.log("\n");
callback(null, a);
}
],
function(err, results)
{
console.log("results of test: " + JSON.stringify(results, null, '\t'));
if (err)
{
console.log("User could not be created.\n" + JSON.stringify(err, null, '\t') + "\n");
}
})*/
}
My test cases are as follows:
userType matching first element of User.userTypes
userType matching another element of User.userTypes (I picked the last one)
userType not matching any of User.userTypes
At runtime, after new User created, User._password is default value and not the value my asynchronous code comes up with for it. I suspect I have some async-sync error, but haven't been able to fix it.
Got it fixed, thanks to #Bergi's advice.
First thing I did: in that async.forEachSeries(), I changed any instance of this to self.
Second thing I did: replaced that asynchronous code (that was working!) to synchronous code. Instead of this:
bcrypt.genSalt(10, function (e, salt) {
bcrypt.hash(password, salt, function (e, hash) {
if (!e)
{
self._password = hash;
if (DEBUG)
{
console.log("this._password ==" + self._password);
console.log("this.userID == " + self.userID);
}
if (typeof cb === 'function')
cb(null, this);
}
else
{
console.log("Error occurred: ");
console.log(e);
if (typeof cb === 'function')
cb(e);
}
})
});
I simply said: this._password = bcrypt.hashSync(password, bcrypt.genSaltSync(10)); and all was good!