Skip to content

Instantly share code, notes, and snippets.

@srveit
Last active January 30, 2024 02:08
Show Gist options
  • Save srveit/28784141cf7a84a115bb to your computer and use it in GitHub Desktop.
Save srveit/28784141cf7a84a115bb to your computer and use it in GitHub Desktop.
File for sending and resending verification codes via Twilio's SMS API
var TWILIO_SID = '<Twilio-SID>',
TWILIO_TOKEN = '<Twilio-token>',
FROM_PHONE = '3143006228',
VERIFICATION_MESSAGE_INTRO = 'Your verification code: ',
TELE_PREFIX = '+1',
twilio = require('twilio'),
Q = require('q'),
_ = require('lodash');
function getPhoneNumber(phone, getOptions) {
var lookups = new twilio.LookupsClient(TWILIO_SID, TWILIO_TOKEN);
return lookups.phoneNumbers(phone).get(getOptions)
.catch(function (error) {
return Promise.reject({
message: 'The phone number ' + phone + ' appears to be invalid.',
error: error
});
});
}
function sendMessage(message) {
var client = new twilio.RestClient(TWILIO_SID, TWILIO_TOKEN);
return client.sendMessage(message)
.then(function (message) {
return message;
})
.catch(function (error) {
return Promise.reject({
message: (error && error.message) || 'sendMessage failed'
});
});
}
function getMessage(messageSid) {
var client = new twilio.RestClient(TWILIO_SID, TWILIO_TOKEN);
return client.accounts.messages(messageSid).get()
.then(function (message) {
return message;
})
.catch(function (error) {
return Q.reject({
message: (error && error.message) || 'getMessage failed'
});
});
}
function logMessage(message) {
console.log('SMS message "' + message.body + '"', message.sid,
'to', message.to, message.status,
message.errorCode || '', message.errorMessage || '');
}
function validatePhoneNumber(options) {
var getOptions = {};
if (options.getCarrier) {
getOptions.type = 'carrier';
}
return getPhoneNumber(options.phone, getOptions)
.catch(function (error) {
logMessage({
body: '',
sid: '',
to: options.phone,
status: 'phone-lookup-failed',
errorMessage: error.message
});
return Promise.reject(error);
})
.then(function(phoneInfo) {
var validationError;
if (phoneInfo.carrier) {
validationError = checkForFraud(phoneInfo);
if (validationError) {
return Promise.reject({message: validationError});
}
}
return phoneInfo;
});
}
function generateVerificationCode(numberDigits) {
var numbers = _.map(new Array(numberDigits), function () {
return Math.floor(Math.random() * (9 - 0 + 1) + 0);
});
return numbers.join('');
}
function waitTillDelivered(message, retries) {
var previousStatus = message.status;
if (retries === undefined) {
retries = 600;
logMessage(message);
}
return getMessage(message.sid).then(function (message) {
if (message.status !== previousStatus) {
logMessage(message);
previousStatus = message.status;
}
if (retries <= 0 ||
message.status === 'failed' ||
message.status === 'received' ||
message.status === 'delivered' ||
message.status === 'undelivered') {
return message;
} else {
return Q.delay(100).then(function () {
return waitTillDelivered(message, retries - 1);
});
}
});
}
function validateSendMessageResponse(message) {
var errorMessage;
if (message.status === 'failed' || message.status === 'undelivered') {
switch (message.errorCode) {
case 30001:
case 30002:
case 30007:
case 30009:
errorMessage = 'Unable to send text message at this time. ' +
'Please try again in a few minutes.';
break;
case 30003:
errorMessage = 'Unable to send text message to given number. ' +
'Please make sure the phone is on and try again.';
default:
errorMessage = 'Unable to send text message to given number. ' +
'Please try again with a different number.';
break;
}
}
if (errorMessage) {
return Promise.reject({message: errorMessage});
}
return message;
}
function deliverMessage(phone, message) {
return sendMessage({
to: '' + phone,
from: TELE_PREFIX + FROM_PHONE,
body: message
})
.then(waitTillDelivered)
.then(validateSendMessageResponse);
}
function checkForFraud(phoneInfo) {
var carrier, carrierName, carrierType, countryCode;
countryCode = phoneInfo.country_code;
carrier = phoneInfo.carrier;
carrierName = carrier && carrier.name;
carrierType = carrier && carrier.type;
// TODO: Business validation logic goes here.
return void 0;
}
function resendVerificationCode(phone) {
var message,
verificationCode = generateVerificationCode(6);
message = VERIFICATION_MESSAGE_INTRO;
message += verificationCode;
console.log('SMS message resend', '"' + message + '"', 'to', phone);
return validatePhoneNumber({phone: phone})
.then(function(phoneInfo) {
return deliverMessage(phoneInfo.phone_number, message);
})
.then(function() {
return {
code: {
string: verificationCode,
isVerified: false
}
};
});
}
function sendVerificationCode(phone, email) {
var country,
message,
verificationCode = generateVerificationCode(6);
message = VERIFICATION_MESSAGE_INTRO;
message += verificationCode;
return validatePhoneNumber({phone: phone, getCarrier: true})
.then(function(phoneInfo) {
country = phoneInfo.country_code;
return deliverMessage(phoneInfo.phone_number, message);
})
.then(function() {
return {
userInfo: {
phone: phone,
email: email,
country: country,
isActivated: false,
isBlocked: false
},
code: {
string: verificationCode,
isVerified: false
}
};
});
}
module.exports.resendVerificationCode = resendVerificationCode;
module.exports.sendVerificationCode = sendVerificationCode;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment