David, thanks for the reply, It actually does handle CVV and all card details, however purely in a test environment and with test card details, it’s more of a proof of concept for both the billing service and the possibility of executing scripts within the dialplan, which I have done before, but not much.
I understand the risks at which this would pose in a production environment and would not deploy it in this way. We will be looking into using a more secure way of handling card details over the phone.
While it is technically a FreePBX machine, none of this dialplan or script utilises any of that, which is why I brought it over to this forum rather than the FreePBX one, please let me know if you believe it belongs over there instead though.
As for the code, please forgive it, I am not a coder, more of a hobbyist!
Dialplan below…
exten => 50000,1,Answer(500)
exten => 50000,n,Set(TimeNow=${EPOCH})
exten => 50000,n,Set(TransID=Trans${TimeNow})
exten => 50000,n(Start),Read(MyVar,/var/lib/asterisk/sounds/en/Recording1,1,,3)
exten => 50000,n,GotoIf($["${MyVar}" = "1"]?Pressed1)
exten => 50000,n,GotoIf($["${MyVar}" = "2"]?Pressed2)
exten => 50000,n,GotoIf($["${MyVar}" = "3"]?Pressed3)
exten => 50000,n,GotoIf($["${MyVar}" = "4"]?Pressed4)
exten => 50000,n,GotoIf($["${MyVar}" = "5"]?Pressed5)
exten => 50000,n,GotoIf($["${MyVar}" != "1"]?NoValid)
exten => 50000,n(Pressed1),Noop(Pressed 1!)
exten => 50000,n,Set(Value=10)
exten => 50000,n,Noop(${Value})
exten => 50000,n,Goto(CardNumber)
exten => 50000,n,Hangup()
exten => 50000,n(Pressed2),Noop(Pressed 2!)
exten => 50000,n,Set(Value=20)
exten => 50000,n,Noop(${Value})
exten => 50000,n,Goto(CardNumber)
exten => 50000,n,Hangup()
exten => 50000,n(Pressed3),Noop(Pressed 3!)
exten => 50000,n,Set(Value=30)
exten => 50000,n,Noop(${Value})
exten => 50000,n,Goto(CardNumber)
exten => 50000,n,Hangup()
exten => 50000,n(Pressed4),Noop(Pressed 4!)
exten => 50000,n,Set(Value=40)
exten => 50000,n,Noop(${Value})
exten => 50000,n,Goto(CardNumber)
exten => 50000,n,Hangup()
exten => 50000,n(Pressed5),Noop(Pressed 5!)
exten => 50000,n,Set(Value=50)
exten => 50000,n,Noop(${Value})
exten => 50000,n,Goto(CardNumber)
exten => 50000,n,Hangup()
#Didnt select any valid option from the IVR, loops to start after telling them its invalid.
exten => 50000,n(NoValid),Noop(Pressed Invalid Number)
exten => 50000,n,Playback(/var/lib/asterisk/sounds/en/Recording5)
exten => 50000,n,Goto(Start)
exten => 50000,n,Hangup()
#This part asks for card number
exten => 50000,n(CardNumber),Noop(Getting Card Number)
exten => 50000,n,Read(CardVar,/var/lib/asterisk/sounds/en/Recording2,17)
exten => 50000,n,Noop(${CardVar})
#This part checks to see if its 16 digits long.
exten => 50000,n,Set(CardLength=${LEN(${CardVar})})
exten => 50000,n,GotoIf($["${CardLength}" = "16"]?ExpiryDate:CardLengthWrong)
#Its not 16 digits long, so it must be wrong, and asks them to do it again(loops here)
exten => 50000,n(CardLengthWrong),Noop(Card Length Wrong, length is ${CardLength})
exten => 50000,n,Goto(CardNumber)
exten => 50000,n,Hangup()
#This part asks for Expiry Date
exten => 50000,n(ExpiryDate),Noop(Getting Expiry Date)
exten => 50000,n,Read(ExpiryVar,/var/lib/asterisk/sounds/en/Recording3,7)
exten => 50000,n,Noop(${ExpiryVar})
#This part checks the length to see if they entered a 4 digit (1219) expiry date or a 6 digit (122019) expiry date, we need it in 6 digit form.
exten => 50000,n,Set(ExpiryLength=${LEN(${ExpiryVar})})
exten => 50000,n,GotoIf($["${ExpiryLength}" = "6"]?ExpDate:wronglengthexpiry)
exten => 50000,n(wronglengthexpiry),Noop(Not 6 digit, is it 4?)
exten => 50000,n,GotoIf($["${ExpiryLength}" = "4"]?fourdigitexpiry:InvalidExpiry)
#Here we have detected the expiry is only 4 digits long, we rip the string apart and add the 20 into the middle.
exten => 50000,n(fourdigitexpiry),Noop(Detected a 4 digit expiry, we will add the 20 in for compatibility)
exten => 50000,n,Set(ExpYear=${ExpiryVar:-2})
exten => 50000,n,Noop(Expiry Year is: ${ExpYear})
exten => 50000,n,Set(ExpMonth=${ExpiryVar:0:2})
exten => 50000,n,Noop(Expiry Month is: ${ExpMonth})
exten => 50000,n,Set(ExpiryVar=${ExpMonth}20${ExpYear})
exten => 50000,n,Noop(Fixed Expiry Date is:${ExpiryVar})
#Time to check if this card is in date.
exten => 50000,n(ExpDate),set(CallYear=${STRFTIME(${EPOCH},GMT,%G)})
exten => 50000,n,Noop(Current Year is ${CallYear})
exten => 50000,n,Set(ExpYear=${ExpiryVar:-4})
exten => 50000,n,Noop(Expiry Year is: ${ExpYear})
exten => 50000,n,GotoIf($["${CallYear}" < "${ExpYear}"]?SecurityCode:ExpMonth)
#Check for out of date Month
#First do we need to check, it would have only got here is its either the same year as now, if it is, we need to check month, if it isnt, something went wrong and we'll start them again.
exten => 50000,n(ExpMonth),set(CallMonth=${STRFTIME(${EPOCH},GMT,%m)})
exten => 50000,n,Noop(Current Month is ${CallMonth})
exten => 50000,n,Set(ExpMonth=${ExpiryVar:0:2})
exten => 50000,n,Noop(Expiry Month is: ${ExpMonth})
exten => 50000,n,GotoIf($["${CallYear}" = "${ExpYear}"]?continue:OutOfDate)
exten => 50000,n,Noop(Expires this year, lets check month)
exten => 50000,n,GotoIf($["${CallMonth}" <= "${ExpMonth}"]?SecurityCode:OutOfDate)
exten => 50000,n,Hangup()
#Card is out of date
exten => 50000,n(OutOfDate),Noop(Card is out of date, Current year is ${CallYear} and card year is ${ExpYear} - Current Month is ${CallMonth} and Card Month is ${ExpMonth})
exten => 50000,n,Playback(/var/lib/asterisk/sounds/en/Recording6)
exten => 50000,n,Goto(ExpiryDate)
#This part is used if expiry was invalid length, not 4 or 6.
exten => 50000,n(InvalidExpiry),Noop(Expiry Length is ${ExpiryLength} this is not valid and not handled, we will ask them to type again.)
exten => 50000,n,Playback(/var/lib/asterisk/sounds/en/Recording6)
exten => 50000,n,Goto(ExpiryDate)
#This part asks for security code
exten => 50000,n(SecurityCode),Noop(Getting Security Code)
exten => 50000,n,Read(SecurityVar,/var/lib/asterisk/sounds/en/Recording4,5)
exten => 50000,n,Noop(${SecurityVar})
exten => 50000,n,Set(ExpMonth=${ExpiryVar:0:2})
exten => 50000,n,Noop(Expiry Month is: ${ExpMonth})
exten => 50000,n,Noop(We are charging ${Value} in pounds to card number: ${CardVar} with expiry Date: ${ExpMonth} ${ExpYear} and Security Code: ${SecurityVar})
exten => 50000,n,Noop(We are going to try and execute my script now!)
exten => 50000,n,AGI(MakePayment.agi,${CardVar},${ExpMonth},${ExpYear},${SecurityVar},${Value},${TransID})
exten => 50000,n,Wait(5)
exten => 50000,n,Set(TestVar123=${FILE(/tmp/log.txt)})
exten => 50000,n,Noop(${TestVar123})
exten => 50000,n,Hangup()
Script below…
#!/usr/bin/perl
use Asterisk::AGI;
# the AGI object
my $agi = new Asterisk::AGI;
#Establishing Variables
#./MakePayment.pl 4242424242424242 12 2019 545 100 -this will make a payment for £100 for that card number.
$CNum = $ARGV[0];
$CExpM = $ARGV[1];
$CExpY = $ARGV[2];
$CCsv = $ARGV[3];
$Value = $ARGV[4];
$TransID = $ARGV[5];
$ResultCode = 999;
#Temp value for testing
#$TransID = Trans1234;
#Write to log for testing
#Getting the Token for our card...
$output = `stripe tokens create card -k ############ --number $CNum --exp-month $CExpM --exp-year $CExpY --cvc $CCsv --name`;
#print $output;
$testforfail = substr $output, 0, 1;
if($testforfail eq '{')
{
#Test for fail has returned { - this means successful token creation
#print $output;
$TokenCreated = "True";
} else
{
$TokenFailure = "True";
}
if($TokenCreated ="True")
{
$token = substr $output, 19, 28;
#print $token;
#print "\n";
$tokenready = "True";
#Retrieve Token
}
if($tokenready = "True")
{
#Time to Create Payment
$paymentoutput = `stripe charge create -k ########## --currency GBP --token $token --amount $Value --description=########`;
#print $paymentoutput
$PaymentDone = "True";
} else {
#print "Failed";
}
if($PaymentDone = "True")
{
#Lets check to see if its successful
if (index($paymentoutput, status => "succeeded") != -1) {
#It was successful
$ResultCode = "1";
#print "Payment Successful";
} else {
#Payment Not Successful - TODO
}
}
if($ResultCode = "1"){
#Payment Successful, tell phone system
my $filename = '/tmp/log.txt';
open(my $fh, '>>', $filename) or die "Could not open file '$filename' $!";
print $fh "$TransID#$ResultCode\n";
close $fh;
}
Some part of the script are not complete, mostly the result code section, however, the script will still run at command line correctly, and as mentioned originally, will also run in the ‘asterisk vc’ mode.