UNPKG

onguard

Version:

RegExp attack-defense & IP-blacklisting for ExpressJS and HarperDB

44 lines (38 loc) 1.66 kB
const {check: type, assert} = require("type-approve") module.exports = class Attack { constructor(patterns) { if(!(this instanceof Attack)) return new Attack(patterns) this.add(patterns) return this } clear() { this.patterns = [] } add(patterns) { assert(type({string: patterns}, {expression: patterns}, {array: patterns}), "Invalid patterns!") if(!type({array: this.patterns})) this.clear() for(const pattern of type({array: patterns}) ? patterns : [patterns]) { assert(type({string: pattern}, {expression: pattern}), `Malformed pattern: ${pattern}`) if(type({string: pattern})) { this.patterns.push(new RegExp(pattern.replace(/\W/g, "\\$&"), "i")) } else { this.patterns.push(pattern) // Could pass pattern straight into RegExp without typechecking but then flags like "gi" could be overridden by the default and mandatory flag "i"! } } return this } match(url) { assert(type({array: this.patterns}) && this.patterns.length > 0, "Missing patterns!") assert(type({string: url}) && url.length > 0, `Invalid url (${typeof url}): ${url}`) const path = new URL(url.toLowerCase(), "http://dummy.domain") let paths = [path.pathname + path.search] try { paths.push(decodeURI(paths[0])) // guard decodeURI because it could throw an error } catch(_) { } return this.patterns.filter(pattern => paths.some(pattern.test.bind(pattern))) } test(url) { return this.match(url).length > 0 } }