UNPKG

shadowsocks-manager

Version:

A shadowsocks manager tool for multi user and traffic control.

220 lines (211 loc) 6.67 kB
const log4js = require('log4js'); const logger = log4js.getLogger('email'); const nodemailer = require('nodemailer'); const rp = require('request-promise'); const config = appRequire('services/config').all(); const knex = appRequire('init/knex').knex; const isInBlackList = appRequire('plugins/email/blackList').isInBlackList; let emailConfig; let transporter; if(!config.plugins.email.type) { config.plugins.email.type = 'smtp'; } if(config.plugins.email.type === 'smtp') { emailConfig = { host: config.plugins.email.host, port: config.plugins.email.port || 465, secure: config.plugins.email.hasOwnProperty('secure') ? config.plugins.email.secure : true, auth: { user: config.plugins.email.username, pass: config.plugins.email.password, }, tls: { rejectUnauthorized: !config.plugins.email.allowUnauthorizedTls, }, proxy: config.plugins.email.proxy || '', }; transporter = nodemailer.createTransport(emailConfig); if(config.plugins.email.proxy && config.plugins.email.proxy.indexOf('socks') >= 0) { transporter.set('proxy_socks_module', require('socks')); } } else if (config.plugins.email.type === 'mailgun') { emailConfig = { baseUrl: config.plugins.email.baseUrl, apiKey: config.plugins.email.apiKey, }; config.plugins.email.email = 'mailgun@' + emailConfig.baseUrl.split('/').slice(-1); const uri = 'https://api:' + emailConfig.apiKey + '@' + emailConfig.baseUrl.split('https://')[1] + '/messages'; transporter = {}; transporter.sendMail = (options, cb) => { rp({ uri, method: 'POST', form: { from: options.from, to: options.to, subject: options.subject, text: options.text, }, }).then(success => { cb(null); }).catch(err => { cb(err); }); }; } else if (config.plugins.email.type === 'sendgrid') { emailConfig = { apiKey: config.plugins.email.apiKey, }; const uri = 'https://api.sendgrid.com/v3/mail/send'; transporter = {}; transporter.sendMail = (options, cb) => { rp({ uri, method: 'POST', json: true, headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${ emailConfig.apiKey }`, }, body: { personalizations: [ { to: [{ email: options.to, }] } ], from: { email: options.from, }, subject: options.subject, content: [{ type: 'text/plain', value: options.text, }] }, }).then(success => { cb(null); }).catch(err => { cb(err); }); }; } const sendMail = async (to, subject, text, options = {}) => { if(isInBlackList(to)) { logger.error('Email in black list: ' + to); return Promise.reject('email in black list'); } const send = (to, subject, text) => { return new Promise((resolve, reject) => { transporter.sendMail({ from: `"${ config.plugins.email.name || '' }" <${ config.plugins.email.email || config.plugins.email.username }>`, to, subject, text, }, (error, info) => { if(error) { return reject(error); } return resolve(info); }); }); }; const checkLimit = async (ip = '', session = '') => { let ipNumber = await knex('email') .where({ ip }) .whereBetween('time', [Date.now() - 3600 * 1000, Date.now()]) .count('time as count').then(success => success[0].count); let sessionNumber = await knex('email') .where({ session }) .whereBetween('time', [Date.now() - 3600 * 1000, Date.now()]) .count('time as count').then(success => success[0].count); if(ip === '127.0.0.1' || !ip) { ipNumber = 0; } if(!session) { sessionNumber = 0; } return ipNumber + sessionNumber; }; const number = await checkLimit(options.ip, options.session); if(number >= 40) { return Promise.reject('send email out of limit'); } await send(to, subject, text); await knex('email').insert({ to, subject, text, type: options.type, remark: options.remark, ip: options.ip, session: options.session, telegramId: options.telegramId, time: Date.now(), }); return; }; const sendCode = async (to, subject = 'subject', text, options = {}) => { const sendEmailTime = 10; try { const findEmail = await knex('email').select(['remark']).where({ to, type: 'code', }).whereBetween('time', [Date.now() - sendEmailTime * 60 * 1000, Date.now()]); if(findEmail.length > 0) { return findEmail[0].remark; } const code = Math.random().toString().substr(2, 6); if(text.indexOf('${code}') >= 0) { text = text.replace(/\$\{code\}/g, '[ ' + code + ' ]'); } else { text += '\n[ ' + code + ' ]'; } await sendMail(to, subject, text, { type: 'code', remark: code, ip: options.ip, session: options.session, telegramId: options.telegramId, }); logger.info(`[${ to }] Send code: ${ code }`); return code; } catch (err) { logger.error(`Send code fail: ${ err }`); return Promise.reject(err); } }; const checkCode = async (email, code) => { logger.info(`[${ email }] Check code: ${ code }`); const sendEmailTime = 10; try { const findEmail = await knex('email').select(['remark']).where({ to: email, remark: code, type: 'code', }).whereBetween('time', [Date.now() - sendEmailTime * 60 * 1000, Date.now()]); if(findEmail.length === 0) { throw new Error('Email or code not found'); } } catch(err) { logger.error(`Check code fail: ${ err }`); return Promise.reject(err); } }; const checkCodeFromTelegram = async (telegramId, code) => { logger.info(`Telegram[${ telegramId }] Check code: ${ code }`); const sendEmailTime = 10; try { const findEmail = await knex('email').where({ telegramId, remark: code, type: 'code', }).whereBetween('time', [Date.now() - sendEmailTime * 60 * 1000, Date.now()]); if(findEmail.length === 0) { throw new Error('Email or code not found'); } return findEmail[0]; } catch(err) { logger.error(`Check code fail: ${ err }`); return Promise.reject(err); } }; exports.checkCodeFromTelegram = checkCodeFromTelegram; exports.checkCode = checkCode; exports.sendCode = sendCode; exports.sendMail = sendMail;