index.js
'use strict';
// this is necessary due to a change in node-fetch that no longer supports require
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
var _ = require('lodash'),
Q = require('q'),
utf8 = require('utf8'),
validator = require('validator');
/**
* StopForumSpam Module
* @exports stopforumspam
* @namespace sfs
*/
var sfs = {
/**
* Default Configuration settings for stopforumspam
*/
config: {
url: 'http://stopforumspam.com',
routes: [{
name: 'search',
path: '/api?f=json&nobadusername' // ignore partial username string search
},{
name: 'submit',
path: '/add.php?api_key=%s'
}],
searchParameters: [{
name: 'ip',
searchAdd: '&ip=%s',
submitAdd: '&ip_addr=%s'
},{
name: 'email',
searchAdd: '&email=%s',
submitAdd: '&email=%s'
},{
name: 'username',
searchAdd: '&username=%s',
submitAdd: '&username=%s'
}],
apiKey: ''
}
};
/**
* Checks if a user is a spammer. Pass only the parameters you wish to search for
* @param userObject {object} a hashlike object with each of the parameters to search for.
* Search for as many or as few as you wish.
* @example
* stopforumspam.isSpammer({ ip: '123.456.789.100', email: 'test@test.com', username: 'Spammer!' })
* .then(function (result) {
* // result if false if not found
* // result = {
* // success: 1,
* // username: {
* // lastseen: '2015-03-09 15:22:49',
* // frequency: 3830,
* // appears: 1,
* // confidence: 90.2 } }
* });
* @returns Promise which returns true if the user is found on StopForumSpam.com
* @throws throws an error if the email or IP is passed and invalid.
* @throws throws any error it recieves from the response, including status codes that are not 200
*/
sfs.isSpammer = function (userObject) {
var deferred = Q.defer();
var url = sfs.config.url + _.find(sfs.config.routes, { name: 'search' }).path;
var fail = false;
_.each(sfs.config.searchParameters, function (parameter) {
if (userObject[parameter.name]) {
if (parameter.name === 'email' && userObject[parameter.name] && !validator.isEmail(userObject[parameter.name])) {
fail = 'email';
}
else if (parameter.name === 'ip' && userObject[parameter.name] && !validator.isIP(userObject[parameter.name])) {
fail = 'ip';
}
url += parameter.searchAdd.replace('%s', encodeURIComponent(utf8.encode(userObject[parameter.name])));
}
});
if (fail) {
if (fail === 'email') {
deferred.reject(new Error('The searched email is not a valid email address'));
}
else if (fail === 'ip') {
deferred.reject(new Error('The searched IP is not a valid IP address'));
}
}
else {
fetch(url)
.then((response) => {
if (response.status !== 200) {
return deferred.reject(new Error('Response Status: ' + response.statusCode));
}
return response.json();
})
.then((jsBody) => {
var result = false;
_.each(sfs.config.searchParameters, function (parameter) {
if (userObject[parameter.name] && jsBody[parameter.name].appears > 0) {
result = jsBody;
}
});
deferred.resolve(result);
}).catch((error) => {
return deferred.reject(error);
});
}
return deferred.promise;
};
/**
* Synchronous version of isSpammer
* Uses ES6 yield trick https://github.com/luciotato/waitfor-ES6#the-funny-thing-is
*/
sfs.isSpammerSync = function* (userObject) {
yield [sfs.isSpammer, userObject];
};
/**
* Submits the user to StopForumSpam.com under your API key
* Requires config.apiKey is set
* @param userObject must contain properties for each searchParameter
* empty parameters will throw an error
* @example
* stopforumspam.Key('some-api-key');
* // or stopforumspam.config.apiKey = 'some-api-key';
* stopforumspam.submit({ ip: '123.456.789.100', email: 'test@test.com', username: 'Spammer!' }, 'Caught You!');
* @param evidence {string} (optional) you can tell StopForumSpam.com your reasoning if you like
* @returns Promise
* @throws throws an error if you have not set the API key
* @throws throws an error if you don't pass a user object with all of the parameters
* (ip, email, & username)
* @throws throws any error it recieves from the response, including status codes that are not 200
*/
sfs.submit = function (userObject, evidence) {
var deferred = Q.defer();
if (!sfs.config.apiKey) {
deferred.reject(new Error('You cannot submit spammers without an API Key.'));
}
else {
var url = sfs.config.url + _.find(sfs.config.routes, { name: 'submit' }).path.replace('%s', sfs.config.apiKey);
var error = false;
_.each(sfs.config.searchParameters, function (parameter) {
if (!userObject[parameter.name]) {
error = true;
}
else {
url += parameter.searchAdd.replace('%s', encodeURIComponent(utf8.encode(userObject[parameter.name])));
}
});
if (error) {
deferred.reject(new Error('You must have all search parameters for StopForumSpam.com to accept your submission.'));
}
else {
if (evidence) {
// unescape in JS is a simple way to convert to UTF-8, which StopForumSpam requires
url += `&evidence=${encodeURIComponent(utf8.encode(evidence))}`;
}
fetch(url)
.then((response) => {
if (response.status !== 200) { return deferred.reject(new Error('Response Status: ' + response.statusCode)); }
deferred.resolve();
}).catch((error) => {
return deferred.reject(error);
});
}
}
return deferred.promise;
};
/**
* Synchronous version of submit
* Uses ES6 yield trick https://github.com/luciotato/waitfor-ES6#the-funny-thing-is
*/
sfs.submitSync = function* (userObject, evidence) {
yield [sfs.submit, userObject, evidence];
};
/**
* Creates a user object to utilize the APi in a more human manner
* @memberOf sfs
* @namespace User
* @param ip {string} the IP address of the user
* @param email {string} the email address of the user
* @param username {string} the username of the user
* @throws throws an error if the email or IP is passed and invalid.
*/
sfs.User = function (ip, email, username) {
if (email && !validator.isEmail(email)) {
throw new Error('The email address is not a valid email address');
}
if (ip && !validator.isIP(ip)) {
throw new Error('The IP address is not a valid IP address');
}
return {
ip: ip,
email: email,
username: username
};
};
/**
* The User object implements isSpammer
* @example
* var sfsUser = stopforumspam.User('123.456.789.100', 'test@test.com', 'Spammer!');
* sfsUser.isSpammer().then(function (result) {
* // do something with result
* });
*/
sfs.User.prototype.isSpammer = function () {
return sfs.isSpammer(this);
};
/**
* The User object implements isSpammerSync
*/
sfs.User.prototype.isSpammerSync = function* () {
yield [this.isSpammer];
};
/**
* The User object implements submit
* @example
* var sfsUser = stopforumspam.User('123.456.789.100', 'test@test.com', 'Spammer!');
* sfsUser.submit();
*/
sfs.User.prototype.submit = function (evidence) {
return sfs.submit(this, evidence);
};
/**
* The User object implements submitSync
*/
sfs.User.prototype.submitSync = function* (evidence) {
yield [this.submit, evidence];
};
/**
* Getter & Setter for the API Key
* @param key {string} The API Key for StopForumSpam.com Necessary for
* submitting users to the database. Unset it with an empty string or false.
* @returns {string} The current API Key as it is set
*/
sfs.Key = function(key) {
if (key !== undefined) {
sfs.config.apiKey = key;
}
return sfs.config.apiKey;
};
module.exports = sfs;