change Blacklist/Whitelist tables to not use ip.toLong to avoid weird results on IPv6

This commit is contained in:
HF 2020-01-08 00:32:55 +01:00
parent 62337771a2
commit 759bffbf1f
9 changed files with 33 additions and 71 deletions

5
package-lock.json generated
View File

@ -6718,11 +6718,6 @@
"resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
"integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY="
},
"ip": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
"integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo="
},
"ip-address": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-6.2.0.tgz",

View File

@ -41,7 +41,6 @@
"global": "^4.3.2",
"hammerjs": "^2.0.8",
"http-proxy-agent": "^3.0.0",
"ip": "^1.1.5",
"ip-address": "^6.2.0",
"isomorphic-fetch": "^2.2.1",
"keycode": "^2.1.9",

View File

@ -2,10 +2,10 @@
* @flow
* */
import IP from 'ip';
import fetch from '../utils/proxiedFetch.js';
import fetch from '../utils/proxiedFetch';
import redis from '../data/redis';
import { getIPv6Subnet } from '../utils/ip';
import { Blacklist, Whitelist } from '../data/models';
import logger from './logger';
@ -108,11 +108,10 @@ async function getCombined(ip: string): Promise<boolean> {
* @return true if blacklisted
*/
async function isBlacklisted(ip: string): Promise<boolean> {
const numIp = IP.toLong(ip);
const count = await Blacklist
.count({
where: {
numIp,
ip,
},
});
return count !== 0;
@ -124,11 +123,10 @@ async function isBlacklisted(ip: string): Promise<boolean> {
* @return true if whitelisted
*/
async function isWhitelisted(ip: string): Promise<boolean> {
const numIp = IP.toLong(ip);
const count = await Whitelist
.count({
where: {
numIp,
ip,
},
});
return count !== 0;
@ -137,7 +135,7 @@ async function isWhitelisted(ip: string): Promise<boolean> {
/*
* dummy function to include if you don't want any proxycheck
*/
async function dummy(ip: string): Promise<boolean> {
async function dummy(): Promise<boolean> {
return false;
}
@ -149,7 +147,8 @@ async function dummy(ip: string): Promise<boolean> {
*/
async function withoutCache(f, ip) {
if (!ip) return true;
return !(await isWhitelisted(ip)) && (await isBlacklisted(ip) || await f(ip));
const ipKey = getIPv6Subnet(ip);
return !(await isWhitelisted(ipKey)) && (await isBlacklisted(ipKey) || await f(ip));
}
/*
@ -160,11 +159,12 @@ async function withoutCache(f, ip) {
* @return true if proxy or blacklisted, false if not or whitelisted
*/
let lock = 4;
const checking = new Array();
const checking = [];
async function withCache(f, ip) {
if (!ip) return true;
// get from cache, if there
const key = `isprox:${ip}`;
const ipKey = getIPv6Subnet(ip);
const key = `isprox:${ipKey}`;
const cache = await redis.getAsync(key);
if (cache) {
const str = cache.toString('utf8');
@ -176,20 +176,20 @@ async function withCache(f, ip) {
// else make asynchronous ipcheck and assume no proxy in the meantime
// use lock to just check three at a time
// do not check ip that currently gets checked
if (checking.indexOf(ip) == -1 && lock > 0) {
if (checking.indexOf(ipKey) == -1 && lock > 0) {
lock -= 1;
checking.push(ip);
checking.push(ipKey);
withoutCache(f, ip)
.then((result) => {
const value = result ? 'y' : 'n';
redis.setAsync(key, value, 'EX', 3 * 24 * 3600); // cache for three days
const pos = checking.indexOf(ip);
const pos = checking.indexOf(ipKey);
if (~pos) checking.splice(pos, 1);
lock += 1;
})
.catch((error) => {
logger.error('PROXYCHECK withCache %s', error.message || error);
const pos = checking.indexOf(ip);
const pos = checking.indexOf(ipKey);
if (~pos) checking.splice(pos, 1);
lock += 1;
});

View File

@ -6,33 +6,17 @@
*/
import DataType from 'sequelize';
import nodeIp from 'ip';
import Model from '../sequelize';
const Blacklist = Model.define('Blacklist', {
numIp: {
type: DataType.INTEGER.UNSIGNED,
ip: {
type: DataType.CHAR(39),
allowNull: false,
primaryKey: true,
},
}, {
getterMethods: {
ip(): string {
return nodeIp.fromLong(this.numIp);
},
},
setterMethods: {
ip(value: string): number {
this.setDataValue('numIp', nodeIp.toLong(value));
},
},
});
export default Blacklist;

View File

@ -7,33 +7,17 @@
*/
import DataType from 'sequelize';
import nodeIp from 'ip';
import Model from '../sequelize';
const Whitelist = Model.define('Whitelist', {
numIp: {
type: DataType.INTEGER.UNSIGNED,
ip: {
type: DataType.CHAR(39),
allowNull: false,
primaryKey: true,
},
}, {
getterMethods: {
ip(): string {
return nodeIp.fromLong(this.numIp);
},
},
setterMethods: {
ip(value: string): number {
this.setDataValue('numIp', nodeIp.toLong(value));
},
},
});
export default Whitelist;

View File

@ -4,7 +4,6 @@
* @flow
*/
import nodeIp from 'ip';
import express from 'express';
import expressLimiter from 'express-limiter';
import type { Request, Response } from 'express';
@ -12,7 +11,7 @@ import bodyParser from 'body-parser';
import sharp from 'sharp';
import multer from 'multer';
import { getIPFromRequest } from '../utils/ip';
import { getIPFromRequest, getIPv6Subnet } from '../utils/ip';
import { getIdFromObject } from '../core/utils';
import redis from '../data/redis';
import session from '../core/session';
@ -64,17 +63,20 @@ router.use(passport.session());
router.use(async (req, res, next) => {
const ip = await getIPFromRequest(req);
if (!req.user) {
logger.info(`${ip} tried to access admintools without login`);
logger.info(`ADMINTOOLS: ${ip} tried to access admintools without login`);
res.status(403).send('You are not logged in');
return;
}
if (!req.user.isAdmin()) {
logger.info(
`${ip} / ${req.user.id} tried to access admintools but isn't Admin`,
`ADMINTOOLS: ${ip}/${req.user.id} wrongfully tried to access admintools`,
);
res.status(403).send('You are not allowed to access this page');
return;
}
logger.info(
`ADMINTOOLS: ${req.user.id} / ${req.user.regUser.name} is using admintools`,
);
next();
});
@ -86,31 +88,32 @@ router.use(async (req, res, next) => {
* @return true if successful
*/
async function executeAction(action: string, ip: string): boolean {
const numIp = nodeIp.toLong(ip);
const key = `isprox:${ip}`;
const ipKey = getIPv6Subnet(ip);
const key = `isprox:${ipKey}`;
logger.info(`ADMINTOOLS: ${action} ${ip}`);
switch (action) {
case 'ban':
await Blacklist.findOrCreate({
where: { numIp },
where: { ip: ipKey },
});
await redis.setAsync(key, 'y', 'EX', 24 * 3600);
break;
case 'unban':
await Blacklist.destroy({
where: { numIp },
where: { ip: ipKey },
});
await redis.del(key);
break;
case 'whitelist':
await Whitelist.findOrCreate({
where: { numIp },
where: { ip: ipKey },
});
await redis.setAsync(key, 'n', 'EX', 24 * 3600);
break;
case 'unwhitelist':
await Whitelist.destroy({
where: { numIp },
where: { ip: ipKey },
});
await redis.del(key);
break;

View File

@ -4,7 +4,6 @@
*/
import type { Request, Response } from 'express';
import nodeIp from 'ip';
import draw from '../../core/draw';
import { blacklistDetector, cheapDetector, strongDetector } from '../../core/isProxy';
@ -83,9 +82,8 @@ async function checkHuman(req: Request, res: Response, next) {
try {
const { token } = req.body;
const numIp = nodeIp.toLong(ip);
const key = `human:${ip}:${ip}`;
const key = `human:${ip}`;
const ttl: number = await redis.ttlAsync(key);
if (ttl > 0) {

View File

@ -4,7 +4,6 @@
* @flow
*/
import nodeIp from 'ip';
import express from 'express';
import expressLimiter from 'express-limiter';
import bodyParser from 'body-parser';

View File

@ -17,7 +17,7 @@ function randomProxyURL() {
return rand;
}
export function fetch(url, options = {}) {
function fetch(url, options = {}) {
if (proxylist.length === 0) {
return isoFetch(url, options);
}