check mail per proxycheck

This commit is contained in:
HF 2022-09-17 17:52:59 +02:00
parent 6dfbe0f25e
commit c4005bbf2e
3 changed files with 93 additions and 38 deletions

View File

@ -16,9 +16,16 @@ import { proxyLogger as logger } from './logger';
import { USE_PROXYCHECK, PROXYCHECK_KEY } from './config'; import { USE_PROXYCHECK, PROXYCHECK_KEY } from './config';
const checker = (USE_PROXYCHECK && PROXYCHECK_KEY) // checker for IP address validity (proxy or vpn or not)
? new ProxyCheck(PROXYCHECK_KEY, logger).checkIp let checker = () => ({ allowed: true, status: 0, pcheck: 'dummy' });
: () => ({ allowed: true, status: 0, pcheck: 'dummy' }); // checker for mail address (disposable or not)
let mailChecker = () => false;
if (USE_PROXYCHECK && PROXYCHECK_KEY) {
const pc = new ProxyCheck(PROXYCHECK_KEY, logger);
checker = pc.checkIp;
mailChecker = pc.checkEmail;
}
/* /*
* save information of ip into database * save information of ip into database
@ -125,7 +132,7 @@ async function withCache(f, ip) {
* check if ip is allowed * check if ip is allowed
* @param ip IP * @param ip IP
* @param disableCache if we fetch result from cache * @param disableCache if we fetch result from cache
* @return { * @return Promise {
* allowed: boolean if allowed to use site * allowed: boolean if allowed to use site
* , status: -2: not yet checked * , status: -2: not yet checked
* -1: whitelisted * -1: whitelisted
@ -143,4 +150,16 @@ function checkIfAllowed(ip, disableCache = false) {
return withCache(checker, ip); return withCache(checker, ip);
} }
/*
* check if email is disposable
* @param email
* @return Promise
* null: some error occured
* false: legit provider
* true: disposable
*/
export function checkIfMailDisposable(email) {
return mailChecker(email);
}
export default checkIfAllowed; export default checkIfAllowed;

View File

@ -5,6 +5,7 @@ import { RegUser } from '../../../data/sql';
import mailProvider from '../../../core/MailProvider'; import mailProvider from '../../../core/MailProvider';
import getMe from '../../../core/me'; import getMe from '../../../core/me';
import { getIPFromRequest, getHostFromRequest } from '../../../utils/ip'; import { getIPFromRequest, getHostFromRequest } from '../../../utils/ip';
import { checkIfMailDisposable } from '../../../core/isAllowed';
import { import {
validateEMail, validateEMail,
validateName, validateName,
@ -17,8 +18,9 @@ import {
async function validate(email, name, password, captcha, captchaid, t, gettext) { async function validate(email, name, password, captcha, captchaid, t, gettext) {
const errors = []; const errors = [];
const emailerror = gettext(validateEMail(email)); const emailerror = gettext(validateEMail(email));
if (emailerror) errors.push(emailerror); if (emailerror) {
if (email.includes('emergentvillage.org') || email.includes('vintomaper')) { errors.push(emailerror);
} else if (await checkIfMailDisposable(email)) {
errors.push(t`This email provider is not allowed`); errors.push(t`This email provider is not allowed`);
} }
const nameerror = validateName(name); const nameerror = validateName(name);

View File

@ -157,6 +157,7 @@ class PcKeyProvider {
} }
/* /*
* TODO: proxycheck added the used burst token to API
* query the API for limits * query the API for limits
* @param key * @param key
*/ */
@ -229,7 +230,7 @@ class ProxyCheck {
* queue of ip-checking tasks * queue of ip-checking tasks
* [[ip, callbackFunction],...] * [[ip, callbackFunction],...]
*/ */
this.ipQueue = []; this.queue = [];
this.fetching = false; this.fetching = false;
this.checkFromQueue = this.checkFromQueue.bind(this); this.checkFromQueue = this.checkFromQueue.bind(this);
this.checkIp = this.checkIp.bind(this); this.checkIp = this.checkIp.bind(this);
@ -237,7 +238,7 @@ class ProxyCheck {
this.logger = logger; this.logger = logger;
} }
reqProxyCheck(ips) { reqProxyCheck(values) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const key = this.pcKeyProvider.getKey(); const key = this.pcKeyProvider.getKey();
if (!key) { if (!key) {
@ -247,7 +248,7 @@ class ProxyCheck {
); );
return; return;
} }
const postData = `ips=${ips.join(',')}`; const postData = `ips=${values.join(',')}`;
const options = { const options = {
hostname: 'proxycheck.io', hostname: 'proxycheck.io',
@ -276,16 +277,17 @@ class ProxyCheck {
const jsonString = data.join(''); const jsonString = data.join('');
const result = JSON.parse(jsonString); const result = JSON.parse(jsonString);
if (result.status !== 'ok') { if (result.status !== 'ok') {
if (result.status === 'error' && ips.length === 1) { if (result.status === 'error' && values.length === 1) {
/* /*
* invalid ip, like a link local address * invalid ip, like a link local address
* Error is either thrown in the top, when requesting only one ip * Error is either thrown in the top, when requesting only one ip
* or in the ip-part as "error": "No valid.." when multiple * or in the ip-part as "error": "No valid.." when multiple
* */ * */
resolve({ resolve({
[ips[0]]: { [values[0]]: {
proxy: 'yes', proxy: 'yes',
type: 'Invalid IP', type: 'Invalid IP',
disposable: 'yes',
}, },
}); });
return; return;
@ -299,11 +301,12 @@ class ProxyCheck {
this.logger.warn(`Warning: ${key}: ${result.message}`); this.logger.warn(`Warning: ${key}: ${result.message}`);
} }
} }
ips.forEach((ip) => { values.forEach((value) => {
if (result[ip] && result[ip].error) { if (result[value] && result[value].error) {
result[ip] = { result[value] = {
proxy: 'yes', proxy: 'yes',
type: 'Invalid IP', type: 'Invalid IP',
disposable: 'yes',
}; };
} }
}); });
@ -330,45 +333,57 @@ class ProxyCheck {
} }
async checkFromQueue() { async checkFromQueue() {
const { ipQueue } = this; const { queue } = this;
if (!ipQueue.length) { if (!queue.length) {
this.fetching = false; this.fetching = false;
return; return;
} }
this.fetching = true; this.fetching = true;
const tasks = ipQueue.slice(0, 50); const tasks = queue.slice(0, 50);
const ips = tasks.map((i) => i[0]); const values = tasks.map((i) => i[0]);
let res = {}; let res = {};
try { try {
res = await this.reqProxyCheck(ips); res = await this.reqProxyCheck(values);
} catch (err) { } catch (err) {
this.logger.error(`Eroor: ${err.message}`); this.logger.error(`Eroor: ${err.message}`);
} }
for (let i = 0; i < tasks.length; i += 1) { for (let i = 0; i < tasks.length; i += 1) {
const task = tasks[i]; const task = tasks[i];
const pos = ipQueue.indexOf(task); const pos = queue.indexOf(task);
if (~pos) ipQueue.splice(pos, 1); if (~pos) queue.splice(pos, 1);
const [ip, cb] = task; const [value, cb] = task;
let allowed = true; if (~value.indexOf('@')) {
let status = -2; // email check
let pcheck = 'N/A'; let disposable = null;
if (res[ip]) { if (res[value]) {
this.logger.info(`${ip}: ${JSON.stringify(res[ip])}`); disposable = !!res[value].disposable;
const { proxy, type, city } = res[ip]; }
allowed = proxy === 'no';
status = (allowed) ? 0 : 1; cb(disposable);
pcheck = `${type},${city}`; } else {
// ip check
let allowed = true;
let status = -2;
let pcheck = 'N/A';
if (res[value]) {
this.logger.info(`${value}: ${JSON.stringify(res[value])}`);
const { proxy, type, city } = res[value];
allowed = proxy === 'no';
status = (allowed) ? 0 : 1;
pcheck = `${type},${city}`;
}
cb({
allowed,
status,
pcheck,
});
} }
cb({
allowed,
status,
pcheck,
});
} }
setTimeout(this.checkFromQueue, 10); setTimeout(this.checkFromQueue, 10);
} }
@ -385,7 +400,26 @@ class ProxyCheck {
*/ */
checkIp(ip) { checkIp(ip) {
return new Promise((resolve) => { return new Promise((resolve) => {
this.ipQueue.push([ip, resolve]); this.queue.push([ip, resolve]);
if (!this.fetching) {
this.checkFromQueue();
}
});
}
/*
* same as for ip
* TODO: cache for mail providers, remember
* a disposable provider for an hour or so
* @param email
* @return Promise that resolves to
* null: failure
* false: is legit provider
* true: is disposable provider
*/
checkEmail(email) {
return new Promise((resolve) => {
this.queue.push([email, resolve]);
if (!this.fetching) { if (!this.fetching) {
this.checkFromQueue(); this.checkFromQueue();
} }