From c4005bbf2ebfc6f37fd55d9e880ea67148e26e19 Mon Sep 17 00:00:00 2001 From: HF Date: Sat, 17 Sep 2022 17:52:59 +0200 Subject: [PATCH] check mail per proxycheck --- src/core/isAllowed.js | 27 +++++++-- src/routes/api/auth/register.js | 6 +- src/utils/ProxyCheck.js | 98 ++++++++++++++++++++++----------- 3 files changed, 93 insertions(+), 38 deletions(-) diff --git a/src/core/isAllowed.js b/src/core/isAllowed.js index 2a2532d..8e6c787 100644 --- a/src/core/isAllowed.js +++ b/src/core/isAllowed.js @@ -16,9 +16,16 @@ import { proxyLogger as logger } from './logger'; import { USE_PROXYCHECK, PROXYCHECK_KEY } from './config'; -const checker = (USE_PROXYCHECK && PROXYCHECK_KEY) - ? new ProxyCheck(PROXYCHECK_KEY, logger).checkIp - : () => ({ allowed: true, status: 0, pcheck: 'dummy' }); +// checker for IP address validity (proxy or vpn or not) +let checker = () => ({ 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 @@ -125,7 +132,7 @@ async function withCache(f, ip) { * check if ip is allowed * @param ip IP * @param disableCache if we fetch result from cache - * @return { + * @return Promise { * allowed: boolean if allowed to use site * , status: -2: not yet checked * -1: whitelisted @@ -143,4 +150,16 @@ function checkIfAllowed(ip, disableCache = false) { 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; diff --git a/src/routes/api/auth/register.js b/src/routes/api/auth/register.js index 926e662..cad6e48 100644 --- a/src/routes/api/auth/register.js +++ b/src/routes/api/auth/register.js @@ -5,6 +5,7 @@ import { RegUser } from '../../../data/sql'; import mailProvider from '../../../core/MailProvider'; import getMe from '../../../core/me'; import { getIPFromRequest, getHostFromRequest } from '../../../utils/ip'; +import { checkIfMailDisposable } from '../../../core/isAllowed'; import { validateEMail, validateName, @@ -17,8 +18,9 @@ import { async function validate(email, name, password, captcha, captchaid, t, gettext) { const errors = []; const emailerror = gettext(validateEMail(email)); - if (emailerror) errors.push(emailerror); - if (email.includes('emergentvillage.org') || email.includes('vintomaper')) { + if (emailerror) { + errors.push(emailerror); + } else if (await checkIfMailDisposable(email)) { errors.push(t`This email provider is not allowed`); } const nameerror = validateName(name); diff --git a/src/utils/ProxyCheck.js b/src/utils/ProxyCheck.js index fd2e994..98dba52 100644 --- a/src/utils/ProxyCheck.js +++ b/src/utils/ProxyCheck.js @@ -157,6 +157,7 @@ class PcKeyProvider { } /* + * TODO: proxycheck added the used burst token to API * query the API for limits * @param key */ @@ -229,7 +230,7 @@ class ProxyCheck { * queue of ip-checking tasks * [[ip, callbackFunction],...] */ - this.ipQueue = []; + this.queue = []; this.fetching = false; this.checkFromQueue = this.checkFromQueue.bind(this); this.checkIp = this.checkIp.bind(this); @@ -237,7 +238,7 @@ class ProxyCheck { this.logger = logger; } - reqProxyCheck(ips) { + reqProxyCheck(values) { return new Promise((resolve, reject) => { const key = this.pcKeyProvider.getKey(); if (!key) { @@ -247,7 +248,7 @@ class ProxyCheck { ); return; } - const postData = `ips=${ips.join(',')}`; + const postData = `ips=${values.join(',')}`; const options = { hostname: 'proxycheck.io', @@ -276,16 +277,17 @@ class ProxyCheck { const jsonString = data.join(''); const result = JSON.parse(jsonString); 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 * Error is either thrown in the top, when requesting only one ip * or in the ip-part as "error": "No valid.." when multiple * */ resolve({ - [ips[0]]: { + [values[0]]: { proxy: 'yes', type: 'Invalid IP', + disposable: 'yes', }, }); return; @@ -299,11 +301,12 @@ class ProxyCheck { this.logger.warn(`Warning: ${key}: ${result.message}`); } } - ips.forEach((ip) => { - if (result[ip] && result[ip].error) { - result[ip] = { + values.forEach((value) => { + if (result[value] && result[value].error) { + result[value] = { proxy: 'yes', type: 'Invalid IP', + disposable: 'yes', }; } }); @@ -330,45 +333,57 @@ class ProxyCheck { } async checkFromQueue() { - const { ipQueue } = this; - if (!ipQueue.length) { + const { queue } = this; + if (!queue.length) { this.fetching = false; return; } this.fetching = true; - const tasks = ipQueue.slice(0, 50); - const ips = tasks.map((i) => i[0]); + const tasks = queue.slice(0, 50); + const values = tasks.map((i) => i[0]); let res = {}; try { - res = await this.reqProxyCheck(ips); + res = await this.reqProxyCheck(values); } catch (err) { this.logger.error(`Eroor: ${err.message}`); } for (let i = 0; i < tasks.length; i += 1) { const task = tasks[i]; - const pos = ipQueue.indexOf(task); - if (~pos) ipQueue.splice(pos, 1); + const pos = queue.indexOf(task); + if (~pos) queue.splice(pos, 1); - const [ip, cb] = task; + const [value, cb] = task; - let allowed = true; - let status = -2; - let pcheck = 'N/A'; + if (~value.indexOf('@')) { + // email check + let disposable = null; - if (res[ip]) { - this.logger.info(`${ip}: ${JSON.stringify(res[ip])}`); - const { proxy, type, city } = res[ip]; - allowed = proxy === 'no'; - status = (allowed) ? 0 : 1; - pcheck = `${type},${city}`; + if (res[value]) { + disposable = !!res[value].disposable; + } + + cb(disposable); + } 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); } @@ -385,7 +400,26 @@ class ProxyCheck { */ checkIp(ip) { 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) { this.checkFromQueue(); }