add ipInfo table

This commit is contained in:
HF 2022-08-01 19:49:13 +02:00
parent d4ef69c2ac
commit e795874893
7 changed files with 134 additions and 30 deletions

View File

@ -11,7 +11,7 @@ import {
import { findIdByNameOrId } from '../data/sql/RegUser';
import ChatMessageBuffer from './ChatMessageBuffer';
import socketEvents from '../socket/SocketEvents';
import { cheapDetector } from './isProxy';
import cheapDetector from './isProxy';
import { DailyCron } from '../utils/cron';
import { escapeMd } from './utils';
import ttags from './ttag';

View File

@ -2,7 +2,8 @@ import fetch from '../utils/proxiedFetch';
import redis from '../data/redis/client';
import { getIPv6Subnet } from '../utils/ip';
import { Blacklist, Whitelist } from '../data/sql';
import whois from '../utils/whois';
import { Blacklist, Whitelist, IPInfo } from '../data/sql';
import { proxyLogger as logger } from './logger';
import { USE_PROXYCHECK } from './config';
@ -37,14 +38,17 @@ async function getIPIntel(ip) {
logger.info('PROXYCHECK fetch getipintel is proxy? %s : %s', ip, body);
// returns tru iff we found 1 in the response and was ok (http code = 200)
const value = parseFloat(body);
return value > 0.995;
return [
value > 0.995,
`score:${value}`,
];
}
/*
* check proxycheck.io if IP is proxy
* Use proxiedFetch with random proxies
* @param ip IP to check
* @return true if proxy, false if not
* @return [ isProxy, info] true if proxy and extra info
*/
async function getProxyCheck(ip) {
const url = `http://proxycheck.io/v2/${ip}?risk=1&vpn=1&asn=1`;
@ -61,7 +65,17 @@ async function getProxyCheck(ip) {
}
const data = await response.json();
logger.info('PROXYCHECK proxycheck is proxy?', data);
return data.status === 'ok' && data[ip].proxy === 'yes';
if (!data.status) {
return [
false,
'status not ok',
];
}
const ipData = data[ip];
return [
ipData.proxy === 'yes',
`${ipData.type},${ipData.city}`,
];
}
/*
@ -98,7 +112,16 @@ async function isWhitelisted(ip) {
* dummy function to include if you don't want any proxycheck
*/
async function dummy() {
return false;
return [false, 'dummy'];
}
async function saveIPInfo(ip, isProxy, info) {
const whoisData = await whois(ip);
IPInfo.upsert({
...whoisData,
isProxy,
pcheck: info,
});
}
/*
@ -116,7 +139,8 @@ async function withoutCache(f, ip) {
if (await isBlacklisted(ipKey)) {
return true;
}
const result = f(ip);
const [result, info] = await f(ip);
saveIPInfo(ip, result, info);
return result;
}
@ -145,33 +169,30 @@ async function withCache(f, ip) {
if (checking.indexOf(ipKey) === -1 && lock > 0) {
lock -= 1;
checking.push(ipKey);
withoutCache(f, ip)
.then((result) => {
const value = result ? 'y' : 'n';
redis.set(key, value, {
EX: 3 * 24 * 3600,
}); // cache for three days
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(ipKey);
if (~pos) checking.splice(pos, 1);
lock += 1;
});
try {
const result = await withoutCache(f, ip);
const value = result ? 'y' : 'n';
redis.set(key, value, {
EX: 3 * 24 * 3600,
}); // cache for three days
const pos = checking.indexOf(ipKey);
if (~pos) checking.splice(pos, 1);
} catch (error) {
logger.error('PROXYCHECK withCache %s', error.message || error);
const pos = checking.indexOf(ipKey);
if (~pos) checking.splice(pos, 1);
} finally {
lock += 1;
}
}
return false;
}
export function cheapDetector(ip) {
function cheapDetector(ip) {
if (USE_PROXYCHECK) {
return withCache(getProxyCheck, ip);
}
return withCache(dummy, ip);
}
export function blacklistDetector(ip) {
return withCache(dummy, ip);
}
export default cheapDetector;

81
src/data/sql/IPInfo.js Normal file
View File

@ -0,0 +1,81 @@
import { DataTypes } from 'sequelize';
import sequelize from './sequelize';
const IPInfo = sequelize.define('IPInfo', {
ip: {
type: DataTypes.CHAR(39),
allowNull: false,
primaryKey: true,
},
uuid: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
allowNull: false,
},
country: {
type: DataTypes.CHAR(2),
defaultValue: 'xx',
allowNull: false,
},
cidr: {
type: DataTypes.CHAR(43),
allowNull: false,
},
org: {
type: DataTypes.CHAR(60),
},
descr: {
type: DataTypes.CHAR(60),
},
asn: {
type: DataTypes.CHAR(12),
allowNull: false,
},
proxy: {
type: DataTypes.TINYINT,
defaultValue: 0,
},
/*
* extra information from
* proxycheck
*/
pcheck: {
type: DataTypes.CHAR(60),
},
}, {
getterMethods: {
isProxy() {
return !!this.proxy;
},
},
setterMethods: {
isProxy(proxy) {
const num = (proxy) ? 1 : 0;
this.setDataValue('proxy', num);
},
org(value) {
this.setDataValue('org', value.slice(0, 60));
},
descr(value) {
this.setDataValue('descr', value.slice(0, 60));
},
pcheck(value) {
this.setDataValue('pcheck', value.slice(0, 60));
},
},
});
export default IPInfo;

View File

@ -5,6 +5,7 @@ import Channel from './Channel';
import UserChannel from './UserChannel';
import Message from './Message';
import UserBlock from './UserBlock';
import IPInfo from './IPInfo';
/*
* User Channel access
@ -43,4 +44,5 @@ export {
UserChannel,
Message,
UserBlock,
IPInfo,
};

View File

@ -7,7 +7,7 @@ import getMe from '../../core/me';
import {
USE_PROXYCHECK,
} from '../../core/config';
import { cheapDetector } from '../../core/isProxy';
import cheapDetector from '../../core/isProxy';
export default async (req, res, next) => {

View File

@ -25,7 +25,7 @@ import chatProvider, { ChatProvider } from '../core/ChatProvider';
import authenticateClient from './authenticateClient';
import { drawByOffsets } from '../core/draw';
import { needCaptcha } from '../data/redis/captcha';
import { cheapDetector } from '../core/isProxy';
import cheapDetector from '../core/isProxy';
const ipCounter = new Counter();

View File

@ -42,7 +42,7 @@ function orgFromWhois(whoisData) {
function parseWhois(ip, whoisData) {
return {
ip,
country: whoisData.country || 'N/A',
country: whoisData.country || 'xx',
cidr: cIDRofWhois(ip, whoisData),
org: orgFromWhois(whoisData),
descr: whoisData.descr || 'N/A',