'use strict'; exports = module.exports = { getBlocklist, setBlocklist }; const assert = require('assert'), BoxError = require('./boxerror.js'), ipaddr = require('ipaddr.js'), path = require('path'), paths = require('./paths.js'), safe = require('safetydance'), settings = require('./settings.js'), shell = require('./shell.js'), validator = require('validator'); const SET_BLOCKLIST_CMD = path.join(__dirname, 'scripts/setblocklist.sh'); function getBlocklist(callback) { assert.strictEqual(typeof callback, 'function'); const data = safe.fs.readFileSync(paths.FIREWALL_BLOCKLIST_FILE, 'utf8'); callback(null, data); } function setBlocklist(blocklist, auditSource, callback) { assert.strictEqual(typeof blocklist, 'string'); assert.strictEqual(typeof auditSource, 'object'); assert.strictEqual(typeof callback, 'function'); const parsedIp = ipaddr.process(auditSource.ip); for (const line of blocklist.split('\n')) { if (!line || line.startsWith('#')) continue; const rangeOrIP = line.trim(); if (!validator.isIP(rangeOrIP) && !validator.isIPRange(rangeOrIP)) return callback(new BoxError(BoxError.BAD_FIELD, `${rangeOrIP} is not a valid IP or range`)); if (rangeOrIP.indexOf('/') === -1) { if (auditSource.ip === rangeOrIP) return callback(new BoxError(BoxError.BAD_FIELD, `${rangeOrIP} includes client IP. Cannot block yourself`)); } else { const parsedRange = ipaddr.parseCIDR(rangeOrIP); if (parsedIp.match(parsedRange)) return callback(new BoxError(BoxError.BAD_FIELD, `${rangeOrIP} includes client IP. Cannot block yourself`)); } } if (settings.isDemo()) return callback(new BoxError(BoxError.CONFLICT, 'Not allowed in demo mode')); if (!safe.fs.writeFileSync(paths.FIREWALL_BLOCKLIST_FILE, blocklist + '\n', 'utf8')) return callback(new BoxError(BoxError.FS_ERROR, safe.error.message)); shell.sudo('setBlocklist', [ SET_BLOCKLIST_CMD ], {}, function (error) { if (error) return callback(new BoxError(BoxError.IPTABLES_ERROR, `Error setting blocklist: ${error.message}`)); callback(); }); }