npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

unspam

v0.0.4

Published

A small little module that prevents spam with 4th grade math.

Downloads

5

Readme

Unspam

Spammers are gross. Get rid of DoS'rs (and maybe even dumb DDoS'rs) with fourth grade math.

What's Unspam?

Unspam is a tiny little Node.js module that keeps track of how many times an IP makes a request. If an IP makes too many requests, Unspam will either ignore the request, or send a 403 error, depending on if the environment is WebSocket or HTTP. (Yes, there is support for both, read on!)

For those who are hungry for information, here's the formula.

{average in milliseconds of time in between requests}/{amount of requests}

I suck at math, I hope you weren't expect calculus or something.

The smaller the number, the spammier the client. Once this number goes below a number that the server has determined, or nothing it put in the default is 0.5, all further requests from that client will be ignored, or sent a 403 error, again depending on the environment.

So, without further ado, here are the only three functions you need to worry about.

unspam.init(options)

Must be called before anything is used. It starts Unspam and will crash without it. The options you can put in it are-

maxRequestRate - a the lowest number the formula above can produce. If a client goes under it, they will be banned.

banTime - How long, in minutes, the client will be banned for. This also doubles for HTTP servers as how long until a user is counted inactive and removed.

cacheInterval - The time in between cache clears, in minutes. When an client's ban expires, it doesn't actually expire. A function must go off periodically and loop through each ban object to check if it has been banTime time since the client was banned. If it has been, it will be removed. If not, nothing will happen.

unspam.expressMiddleware

It's Express middleware. Woo.

const express = require('express')
const app = express()
const unspam = require('unspam')

unspam.init({maxRequestRate:0.5,expiry:60,cacheInterval:30000})

app.use(unspam.expressMiddleware)

app.get('/', function(req, res) {
    res.send('hello!') 
    /* A spammy user would not get a nice hello message, 
    they would get a 403 forbidden error.
    */
})

unspam.attachSocket(socket, callback)

Okay, I tried and I tried to make this not have to have a callback, but it was hard. If anyone can find a better way to do this, please tell me. I hate callbacks as much as the next guy.

I programmed this with the ws module in mind, so I don't know how much it will work with other modules. The first argument is the object returned by the callback in websocketServer.on('connection', function(ws) { } . That ws object is important, and is what will be put in the function.

The second one is, *gasp!*, a callback. Pretty much, if the function finds out that client is banned, the callback will not be called. At all, period. It will also remove all event listeners for that client and that client only.

Here, have an example.

const WebSocket = require('ws').Server
const wss = new Websocket({port:'the port, i guess'})

const unspam = require('unspam')
unspam.init({maxRequestRate:0.5,expiry:60,cacheInterval:30000})

wss.on('connection', function(ws) {
    unspam.attachSocket(ws, function() {
        ws.on('message', function(message) {
            console.log(message)
        })
    })
})

Yes, it looks like a pyramid, but it works for now. It will detect if a user is spamming messages, and if they are, they get the boot. Anytime a user disconnects or crashes, they are removed from the watch list.

unspam.bans

An array of objects. In each object, there are two properties, ip, and time. ip is the amount of innings pitched (or the address of the user who got banned, if you don't have a sense of humor), and time is the time the user got banned, presented in milliseconds since January 1, 1970.

There are more functions, but these should be good for general uses. A lot of them are just manual interaction with banning and accounting for client request speed, and should only be used if a middleware for your server is not provided.

I plan to add more middlewares (Koa, Hapi) sometime soon, and maybe even support other WebSocket modules, but for now, Ciao!

-Flarp

(I've also commented the source code, so give it a look!)