2020-01-02 16:58:06 +00:00
/ *
* functions for mail verify
* /
2021-01-30 12:32:46 +00:00
/* eslint-disable max-len */
2020-01-06 10:46:11 +00:00
import nodemailer from 'nodemailer' ;
2020-01-02 16:58:06 +00:00
2020-01-06 10:46:11 +00:00
import logger from './logger' ;
2021-01-30 12:32:46 +00:00
import { getTTag } from './ttag' ;
2022-09-09 22:35:28 +00:00
import { codeExists , checkCode , setCode } from '../data/redis/mailCodes' ;
import socketEvents from '../socket/socketEvents' ;
2022-06-30 09:47:36 +00:00
import { USE _MAILER , MAIL _ADDRESS } from './config' ;
2020-01-02 16:58:06 +00:00
2022-06-19 21:19:10 +00:00
import { RegUser } from '../data/sql' ;
2020-01-02 16:58:06 +00:00
2022-09-09 22:35:28 +00:00
export class MailProvider {
2020-01-02 16:58:06 +00:00
constructor ( ) {
2022-06-30 09:47:36 +00:00
this . enabled = ! ! USE _MAILER ;
if ( this . enabled ) {
this . transporter = nodemailer . createTransport ( {
sendmail : true ,
newline : 'unix' ,
path : '/usr/sbin/sendmail' ,
} ) ;
}
2022-09-09 22:35:28 +00:00
/ *
* mail requests make it through SocketEvents when sharding
* /
socketEvents . on ( 'mail' , ( type , args ) => {
switch ( type ) {
case 'verify' :
this . postVerifyMail ( ... args ) ;
break ;
case 'pwreset' :
this . postPasswdResetMail ( ... args ) ;
break ;
default :
// nothing
}
} ) ;
2022-06-30 09:47:36 +00:00
}
2020-01-02 16:58:06 +00:00
2022-06-30 09:47:36 +00:00
sendMail ( to , subject , html ) {
if ( ! this . enabled ) {
return ;
}
this . transporter . sendMail ( {
from : ` PixelPlanet < ${ MAIL _ADDRESS } > ` ,
to ,
replyTo : MAIL _ADDRESS ,
subject ,
html ,
} , ( err ) => {
if ( err ) {
logger . error ( err ) ;
}
} ) ;
2020-01-02 16:58:06 +00:00
}
2022-09-09 22:35:28 +00:00
postVerifyMail ( to , name , host , lang , code ) {
2021-01-30 12:32:46 +00:00
const { t } = getTTag ( lang ) ;
2020-01-02 16:58:06 +00:00
logger . info ( ` Sending verification mail to ${ to } / ${ name } ` ) ;
2022-09-09 22:35:28 +00:00
const verifyUrl = ` ${ host } /api/auth/verify?token= ${ code } &email= ${ encodeURIComponent ( to ) } ` ;
2023-03-13 00:05:46 +00:00
const subject = t ` Welcome ${ name } to PixelPlanet, please verify your mail ` ;
2022-06-30 09:47:36 +00:00
const html = ` <em> ${ t ` Hello ${ name } ` } </em>,<br />
2021-01-30 12:32:46 +00:00
$ { t ` welcome to our little community of pixelplacers, to use your account, you have to verify your mail. You can do that here: ` } < a href = "${verifyUrl}" > $ { t ` Click to Verify ` } < /a>. ${t`Or by copying following url:`}<br / > $ { verifyUrl } \ n < br / >
2023-03-13 00:05:46 +00:00
$ { t ` Have fun and don't hesitate to contact us if you encounter any problems :) ` } < br / >
2021-01-30 12:32:46 +00:00
$ { t ` Thanks ` } < br / > < br / >
2023-12-13 09:57:12 +00:00
< img alt = "" src = "https://pixelplanet.fun/tile.png" style = "height:64px; width:64px" / > ` ;
2022-06-30 09:47:36 +00:00
this . sendMail ( to , subject , html ) ;
2022-09-09 22:35:28 +00:00
}
async sendVerifyMail ( to , name , host , lang ) {
if ( ! this . enabled && ! socketEvents . isCluster ) {
return null ;
}
const { t } = getTTag ( lang ) ;
const pastCodeAge = await codeExists ( to ) ;
if ( pastCodeAge && pastCodeAge < 180 ) {
const minLeft = Math . ceil ( ( 180 - pastCodeAge ) / 60 ) ;
logger . info (
` Verify mail for ${ to } - already sent, ${ minLeft } minutes left ` ,
) ;
return t ` We already sent you a verification mail, you can request another one in ${ minLeft } minutes. ` ;
}
const code = setCode ( to ) ;
if ( this . enabled ) {
this . postVerifyMail ( to , name , host , lang , code ) ;
} else {
socketEvents . sendMail ( 'verify' , [ to , name , host , lang , code ] ) ;
}
2020-01-02 16:58:06 +00:00
return null ;
}
2022-09-09 22:35:28 +00:00
postPasswdResetMail ( to , ip , host , lang , code ) {
2021-01-30 12:32:46 +00:00
const { t } = getTTag ( lang ) ;
2022-09-09 22:35:28 +00:00
logger . info ( ` Sending Password reset mail to ${ to } ` ) ;
2022-09-11 00:21:49 +00:00
const restoreUrl = ` ${ host } /reset_password?token= ${ code } &email= ${ encodeURIComponent ( to ) } ` ;
2022-09-09 22:35:28 +00:00
const subject = t ` You forgot your password for PixelPlanet? Get a new one here ` ;
const html = ` <em> ${ t ` Hello ` } </em>,<br />
$ { t ` You requested to get a new password. You can change your password within the next 30min here: ` } < a href = "${restoreUrl}" > $ { t ` Reset Password ` } < /a>. ${t`Or by copying following url:`}<br / > $ { restoreUrl } \ n < br / >
$ { t ` If you did not request this mail, please just ignore it (the ip that requested this mail was ${ ip } ). ` } < br / >
2023-12-13 09:57:12 +00:00
$ { t ` Thanks ` } < br / > < br / > \ n < img alt = "" src = "https://pixelplanet.fun/tile.png" style = "height:64px; width:64px" / > ` ;
2022-09-09 22:35:28 +00:00
this . sendMail ( to , subject , html ) ;
}
2022-06-30 09:47:36 +00:00
2022-09-09 22:35:28 +00:00
async sendPasswdResetMail ( to , ip , host , lang ) {
const { t } = getTTag ( lang ) ;
if ( ! this . enabled && ! socketEvents . isCluster ) {
2022-06-30 09:47:36 +00:00
return t ` Mail is not configured on the server ` ;
}
2022-09-09 22:35:28 +00:00
const pastCodeAge = await codeExists ( to ) ;
if ( pastCodeAge && pastCodeAge < 180 ) {
logger . info (
` Password reset mail for ${ to } requested by ${ ip } - already sent ` ,
) ;
return t ` We already sent you a mail with instructions. Please wait before requesting another mail. ` ;
2020-01-02 16:58:06 +00:00
}
2022-09-09 22:35:28 +00:00
2020-01-02 16:58:06 +00:00
const reguser = await RegUser . findOne ( { where : { email : to } } ) ;
2022-09-09 22:35:28 +00:00
if ( ! reguser ) {
2020-01-06 10:46:11 +00:00
logger . info (
` Password reset mail for ${ to } requested by ${ ip } - mail not found ` ,
) ;
2021-01-30 12:32:46 +00:00
return t ` Couldn't find this mail in our database ` ;
2020-01-02 16:58:06 +00:00
}
2022-06-30 09:47:36 +00:00
2020-01-02 16:58:06 +00:00
/ *
* not sure if this is needed yet
2023-03-13 00:05:46 +00:00
* does it matter if spamming password reset mails or verifications mails ?
2020-01-02 16:58:06 +00:00
*
if ( ! reguser . verified ) {
logger . info ( ` Password reset mail for ${ to } requested by ${ ip } - mail not verified ` ) ;
return "Can't reset password of unverified account." ;
}
* /
2022-09-09 22:35:28 +00:00
const code = setCode ( to ) ;
if ( this . enabled ) {
this . postPasswdResetMail ( to , ip , host , lang , code ) ;
} else {
socketEvents . sendMail ( 'pwreset' , [ to , ip , host , lang , code ] ) ;
2020-01-02 16:58:06 +00:00
}
2022-09-09 22:35:28 +00:00
return null ;
2020-01-02 16:58:06 +00:00
}
2022-09-09 22:35:28 +00:00
static async verify ( email , code ) {
const ret = await checkCode ( email , code ) ;
if ( ! ret ) {
2020-01-02 16:58:06 +00:00
return false ;
}
const reguser = await RegUser . findOne ( { where : { email } } ) ;
if ( ! reguser ) {
logger . error ( ` ${ email } does not exist in database ` ) ;
return false ;
}
await reguser . update ( {
mailVerified : true ,
verificationReqAt : null ,
} ) ;
2020-04-30 01:20:31 +00:00
return reguser . name ;
2020-01-02 16:58:06 +00:00
}
2022-09-09 22:35:28 +00:00
/ *
* we do not use this right now
2020-01-06 10:46:11 +00:00
static cleanUsers ( ) {
2023-03-13 00:05:46 +00:00
// delete users that require verification for more than 4 days
2020-01-02 16:58:06 +00:00
RegUser . destroy ( {
where : {
verificationReqAt : {
2020-01-06 10:46:11 +00:00
[ Sequelize . Op . lt ] :
Sequelize . literal ( 'CURRENT_TIMESTAMP - INTERVAL 4 DAY' ) ,
2020-01-02 16:58:06 +00:00
} ,
verified : 0 ,
} ,
} ) ;
}
2022-09-09 22:35:28 +00:00
* /
2020-01-02 16:58:06 +00:00
}
2020-01-06 11:29:33 +00:00
const mailProvider = new MailProvider ( ) ;
2020-01-02 16:58:06 +00:00
export default mailProvider ;