Last active
January 30, 2024 02:08
-
-
Save srveit/28784141cf7a84a115bb to your computer and use it in GitHub Desktop.
File for sending and resending verification codes via Twilio's SMS API
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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