2024-03-20 12:49:49 +00:00
|
|
|
const UserError = require('vn-loopback/util/user-error');
|
|
|
|
const OTP_CHAR = ':';
|
|
|
|
function original({id, phone}) {
|
2024-03-20 13:11:05 +00:00
|
|
|
const total = parseInt(phone) + parseInt(id);
|
|
|
|
const value = total.toString().slice(-6);
|
2024-03-20 12:49:49 +00:00
|
|
|
|
2024-03-20 13:11:05 +00:00
|
|
|
return parseInt(value); // Devolvemos un número entero, no una cadena
|
2024-03-20 12:49:49 +00:00
|
|
|
}
|
|
|
|
function reverse(params) {
|
|
|
|
const _original = original(params);
|
|
|
|
return parseInt(_original.toString().split('').reverse().join(''));
|
|
|
|
}
|
|
|
|
|
2024-03-20 13:11:05 +00:00
|
|
|
function selectOTPMethod() {
|
2024-03-20 12:49:49 +00:00
|
|
|
const otpIndex = Math.floor(Math.random() * Object.keys(OTP_TYPES).length);
|
2024-03-20 13:11:05 +00:00
|
|
|
return Object.keys(OTP_TYPES)[otpIndex];
|
|
|
|
}
|
|
|
|
function generateOTP(params, _otpType, format = true) {
|
|
|
|
const otpType = _otpType ?? selectOTPMethod();
|
2024-03-20 12:49:49 +00:00
|
|
|
const otp = OTP_TYPES[otpType](params);
|
2024-03-20 13:11:05 +00:00
|
|
|
if (format) return formatOTP({otpType, otp});
|
|
|
|
return {otpType, otp};
|
2024-03-20 12:49:49 +00:00
|
|
|
}
|
|
|
|
|
2024-03-20 13:11:05 +00:00
|
|
|
function formatOTP({otpType, otp}) {
|
|
|
|
return `${otpType}${OTP_CHAR}${otp}`;
|
2024-03-20 12:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function checkOTP(params, otp) {
|
|
|
|
const [otpType, value] = otp.split(OTP_CHAR);
|
|
|
|
return generateOTP(params, otpType) === formatOTP(otpType, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
const OTP_TYPES = {
|
|
|
|
// 'A': original,
|
|
|
|
'B': reverse,
|
|
|
|
};
|
|
|
|
module.exports = Self => {
|
|
|
|
Self.remoteMethod('recoverPasswordSMS', {
|
|
|
|
description: 'Send SMS to the user',
|
|
|
|
accepts: [
|
|
|
|
{
|
|
|
|
arg: 'ctx',
|
|
|
|
type: 'Object',
|
|
|
|
http: {source: 'context'}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
arg: 'id',
|
|
|
|
type: 'string',
|
|
|
|
description: 'The user id',
|
|
|
|
required: true
|
|
|
|
},
|
|
|
|
{
|
|
|
|
arg: 'phone',
|
|
|
|
type: 'string',
|
|
|
|
description: 'The user name or email',
|
|
|
|
required: true
|
|
|
|
},
|
|
|
|
{
|
|
|
|
arg: 'otp',
|
|
|
|
type: 'string',
|
|
|
|
description: 'The directory for mail'
|
|
|
|
}
|
|
|
|
],
|
|
|
|
returns: {
|
|
|
|
type: 'Object',
|
|
|
|
root: true
|
|
|
|
},
|
|
|
|
http: {
|
|
|
|
path: `/recoverPasswordSMS`,
|
|
|
|
verb: 'POST'
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2024-03-20 13:11:05 +00:00
|
|
|
Self.recoverPasswordSMS = async function(ctx, id, phone, _otp) {
|
2024-03-20 12:49:49 +00:00
|
|
|
const usesPhone = new RegExp(/([+]\d{2})?\d{9}/, 'g').test(+phone);
|
|
|
|
|
|
|
|
if (!usesPhone) throw new UserError('Phone not valid');
|
|
|
|
|
|
|
|
let query = {
|
|
|
|
fields: ['id', 'phone', 'email'],
|
|
|
|
where: {id, phone}
|
|
|
|
};
|
|
|
|
|
|
|
|
const user = await Self.findOne(query);
|
|
|
|
if (!user) throw new UserError('Credentials not valid');
|
|
|
|
|
|
|
|
try {
|
2024-03-20 13:11:05 +00:00
|
|
|
if (_otp) {
|
2024-03-20 12:49:49 +00:00
|
|
|
return {
|
2024-03-20 13:11:05 +00:00
|
|
|
valid: checkOTP(query.where, _otp),
|
2024-03-20 12:49:49 +00:00
|
|
|
token: await user.accessTokens.create({})
|
|
|
|
};
|
|
|
|
}
|
2024-03-20 13:11:05 +00:00
|
|
|
// ONLY FOR TESTS
|
|
|
|
// return {otp: generateOTP(query.where)};
|
|
|
|
|
|
|
|
// AFTER TESTS
|
|
|
|
// const otp = generateOTP(query.where, null, false);
|
|
|
|
// await Self.app.models.Sms.send({req: {accessToken: {userId: id}}}, +phone, formatOTP(otp));
|
|
|
|
// return {otp: otp.otpType};
|
2024-03-20 12:49:49 +00:00
|
|
|
} catch (err) {
|
|
|
|
if (err.code === 'EMAIL_NOT_FOUND')
|
|
|
|
return;
|
|
|
|
else
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|