Additional modules for fraud protection
From ISPWiki
BILLmanager allows you to add custom module handlers. The fraud system module structure contains two files:
- The XML file that describes the interface called billmgr_mod_xxx.xml, (where xxx is random symbol) that is used how to set up connection parameters. The file should locate in the {path to installation folder}/etc/ directory and should be encoded in the UTF-8 character set.
- The binary or test file (depending the language) of a module handler. The file should locate in the /usr/local/ispmgr/sbin/ directory, and its name should start with fp.
Contents |
XML file structure
An XML consists of two parts:
- Description of the parameter form
- Localized fields
<?xml version="1.0" encoding="UTF-8"?> <mgrdata> <metadata name="fraudparam_xxx" type="form"> <!-- xxx - имя вашего модуля без '''fp''' --> <form> <!--Configuration fields required for your module, which are displayed when entering parameters of the module--> <field name="field_name_1"> <input type="text" name="field_name_1"/> </field> <!--...--> <field name="field_name_n"> <input type="text" name="field_name_n"/> </field> </form> </metadata> <metadata name="smsgateparam_xxx" type="form"> <!-- xxx - name of your module without '''fp'''. This module is required if you are going to use it as an SMS gateway --> <form> <!--Configuration fields required for your module, which are displayed when entering parameters of the module--> <field name="field_name_1"> <input type="text" name="field_name_1"/> </field> <!--...--> <field name="field_name_n"> <input type="text" name="field_name_n"/> </field> </form> </metadata> <lang name="en"> <!-- Several languages must the described in an XML document. The English language is obligatory --> <messages name="fraudconf"> <msg name="xxx">XXX</msg> <!-- xxx - name of your module without '''fp''', XXX - name of the module on the list --> </messages> <messages name="fraudparam_xxx"> <!-- xxx - name of your module without '''fp''' --> <msg name="title">Title</msg> <!-- title of the input box --> <msg name="field_name_1">field name 1</msg> <!-- name of module settings' field --> <msg name="hint_field_name_1">hint field name 1</msg> <!-- hint that is displayed when moving the mouse cursor over the field' name --> <!--...--> <msg name="field_name_n">field name n</msg> <msg name="hint_field_name_n">hint field name n</msg> </messages> <messages name="smsgateparam_xxx"> <!-- xxx - name of your module without '''fp'''. This module is required if you are going to use it as an SMS gateway --> <msg name="title">Title</msg> <!-- title of the input box --> <msg name="field_name_1">field name 1</msg> <!-- name of module settings' field --> <msg name="hint_field_name_1">hint field name 1</msg> <!-- hint that is displayed when moving the mouse cursor over the field' name --> <!--...--> <msg name="field_name_n">field name n</msg> <msg name="hint_field_name_n">hint field name n</msg> </messages> </lang> <lang name="ru"> <!--The same parameters for another language--> </lang> </mgrdata>
Module structure
BILLmanager passes the data to a module file via the command line parameters.
The handler module must process the command line parameters and respond to the commands.
The module configuration parameters are located in the '{path to installation folder}/etc/fpxxx.conf (sgxxx{partner ID}.conf - to set up an SMS gateway), where xxx is a module name in the format: <parameter name> <value>. Each parameter is specified in a separate line.
Received parameters and commands
- features - a list of supported features should be passed to STDIN: fraud and/orgate, for example: "fraud gate".
- validate - check the data and pass 'ok' to STDOUT.
- tune - if necessary, pass the XML document describing the interface to STDOUT.
- type - pass a module type: 'sms', if an SMS is to be sent, or 'call', if a call is to be made.
- call - call the handler to send an SMS or make a call. The full version looks like this 'fpxxx call ccode phone code lang', where call is a master command, ccode is a country code in the phone number (the first line received when verifying a phone number), phone is a phone number, code is a verification code, lang is a default user language.
- sendsms - the command to pass an SMS; possible parameters: partnerid' phone' and a message text, where 'partnerid' is a partner account's identifier, if an sms is sent to a partner's client; 'phone' is a phone number to which the sms should be sent.
- If completed successfully, call the command '{path to installation folder}/sbin/mgrctl -m billmgr -o xml longtask.finish elid=(PID of startup file) status=ok'. Once the sms has been successfully sent, pass "OK" to STDOUT, otherwise send "ERROR".
- If not, call the command '{path to installation folder}/sbin/mgrctl -m billmgr -o xml longtask.finish elid=(PID of the startup file) status=err errmsg=(text of the error message)'
More information can be found in the article LongTask
Example
Consider creating a module script for connecting to API TextMagic (the XML text given below is only an example, you must replace it with valid parameters).
XML document
The XML document:
<?xml version="1.0" encoding="UTF-8"?> <mgrdata> <metadata name="fraudparam_textmagic" type="form"> <form>
Following are the module configuration parameters: <field name="username">
<input type="text" name="username" empty="no"/> </field> <field name="password"> <input type="text" name="password" empty="no"/> </field> <field name="phonereg"> <input type="text" name="phonereg"/> </field> </form> </metadata> <metadata name="smsgateparam_textmagic" type="form"> <form>
Following are the sms gateway configuration parameters:
<field name="username"> <input type="text" name="username" empty="no"/> </field> <field name="password"> <input type="text" name="password" empty="no"/> </field> </form> </metadata>
Example in English:
<lang name="en"> <messages name="fraudconf"> <msg name="textmagic">Text Magic</msg> </messages> <messages name="fraudparam_textmagic"> <msg name="title">Phone check from Text Magic</msg> <msg name="username">User name</msg> <msg name="hint_username">Specify a user name</msg> <msg name="password">Password</msg> <msg name="hint_password">Specify a password</msg> <msg name="phonereg">Phone filter</msg> <msg name="hint_phonereg">Specify a phone filter. This field can be empty.</msg> </messages> <messages name="smsgateparam_textmagic"> <msg name="title">SMS gate from Text Magic</msg> <msg name="username">User name</msg> <msg name="hint_username">Specify a user name</msg> <msg name="password">Password</msg> <msg name="hint_password">Specify a password</msg> </messages> </lang>
Example in Russian:
<lang name="ru"> <messages name="fraudconf"> <msg name="textmagic">Text Magic</msg> </messages> <messages name="fraudparam_textmagic"> <msg name="title">Проверка телефона от Text Magic</msg> <msg name="username">Имя пользователя</msg> <msg name="hint_username">Укажите имя пользователя</msg> <msg name="password">Пароль</msg> <msg name="hint_password">Укажите пароль</msg> <msg name="phonereg">Фильтр номеров</msg> <msg name="hint_phonereg">Укажите фильтр разрешенных номеров телефонов. Поле можно оставить пустым</msg> </messages> <messages name="smsgateparam_textmagic"> <msg name="title">СМС шлюз от Text Magic</msg> <msg name="username">Имя пользователя</msg> <msg name="hint_username">Укажите имя пользователя</msg> <msg name="password">Пароль</msg> <msg name="hint_password">Укажите пароль</msg> </messages> </lang> </mgrdata>
Script handler
Script handler written in PHP
#!/usr/bin/php <?php
Set your error handler for logging errors instead of passing them to STDOUT:
set_error_handler("tmErrorHandler");
Open the log file:
$log_file = fopen("/usr/local/ispmgr/var/fptextmagic.log", "a");
fwrite($log_file, "=======".date("M j H:i:s") . "[] " ."=======\n");
Enter the parameters into the log file:
foreach($argv as $line_num => $line) {
fwrite($log_file, date("M j H:i:s") . "[] " . $line_num.":".$line."\n");
}
Process the received parameters (the first parameter is a startup file), if the number of received parameters is less than 2, you need to output the information concerning the module usage. 3 or 4 parameters are passed for the 'call' command, thus the module must receive 4 or 5 parameters.
if ($argc<2) {
usage();
} else {
switch($argv[1]) {
Output 'ok':
case "features": echo "fraud gate"; break; case "validate": echo "ok"; break; case "tune":
Output the module type sms:
case "type": echo "sms"; break;
Call the handler for sending SMS:
case "call":
if ($argc<5 || $argc>6) {
fwrite($log_file, date("M j H:i:s") . "[] " . "Invalid params number." . "\n");
usage();
} else {
fwrite($log_file, date("M j H:i:s") . "[] " . "Start call API." . "\n");
if ($argc == 4) {
callfraud($argv[2] . $argv[3], $argv[4]);
} else {
callfraud($argv[2] . $argv[3], $argv[4], $argv[5]);
}
}
break;
case "sendsms":
if ($argc != 3) {
fwrite($log_file, date("M j H:i:s") . "[] " . "Invalid params number." . "\n");
usage();
} else {
fwrite($log_file, date("M j H:i:s") . "[] " . "Start call API." . "\n");
$msg;
$f = fopen('php://stdin', 'r');
while ($line = fgets($f))
$msg .= $line;
callgate($argv[2], $argv[3], $msg);
}
break;
default:
usage();
}
}
fwrite($log_file, "=======".date("M j H:i:s") . "[] " ."=======\n");
fclose($log_file);
The module usage output function:
function usage() {
print("ISPsystem BILLmanager plugin v1.0
Text Magic integration plugin.
Usage:
features - print 'fraud gate';
validate - print 'ok';
tune - no return value;
type - return 'sms' as type of plugin;
sendsms 'partnerid' 'phone_number' <msg> - send sms to phone number;
call 'country_code' 'phone_number' 'verification_code' 'lang' - execute plugin function.\n");
}
SMS processing function for fraud protection:
function callfraud($phone, $code, $lang = "en") {
global $log_file;
fwrite($log_file, date("M j H:i:s") . "[] " . "Phone: " . $phone . " Code: " . $code . "\n");
$msg = "Your verification code is ".$code;
Get parameters from the configuration file:
$lines = file("/usr/local/ispmgr/etc/fptextmagic.conf", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$params = array();
foreach ($lines as $line_num => $line) {
$arr_key = "";
$arr_val = "";
list($arr_key, $arr_val) = explode(" ", $line, 2);
$params += array($arr_key => $arr_val);
}
$curl_client = curl_init("https://www.textmagic.com/app/api");
fwrite($log_file, date("M j H:i:s") . "[] " . curl_error($curl_client) . "\n");;
Form the array to pass to the server.
$data = array("username" => $params["username"], "password" => $params["password"], "cmd" => "send",
"text" => $msg, "phone" => $phone, "unicode" => "0");
curl_setopt($curl_client, CURLOPT_SSL_VERIFYPEER, 0);
fwrite($log_file, date("M j H:i:s") . "[] " . curl_error($curl_client) . "\n");
curl_setopt($curl_client, CURLOPT_POST, 1);
fwrite($log_file, date("M j H:i:s") . "[] " . curl_error($curl_client) . "\n");
curl_setopt($curl_client, CURLOPT_POSTFIELDS, $data);
fwrite($log_file, date("M j H:i:s") . "[] " . curl_error($curl_client) . "\n");
$output = curl_exec($curl_client); //В случае успешного завершения запроса в $output помещается 1, в противном случае ничего.
fwrite($log_file, date("M j H:i:s") . "[] " . curl_error($curl_client) . "\n");
fwrite($log_file, date("M j H:i:s") . "[] " . $output . "\n");
Finish the module:
fwrite($log_file, date("M j H:i:s") . "[] Finish task with PID file " . getenv("MGR_LT_PID") . "\n");
if ($output == "1") {
exec("/usr/local/ispmgr/sbin/mgrctl -m billmgr -o xml longtask.finish elid=". getenv("MGR_LT_PID") ." status=ok");
} else {
exec("/usr/local/ispmgr/sbin/mgrctl -m billmgr -o xml longtask.finish elid=". getenv("MGR_LT_PID") ." status=err errmsg='Error with cURL'");
}
curl_close($curl_client);
}
SMS send function (as a gateway):
function callgate($partnerid, $phone, $msg) {
global $log_file;
fwrite($log_file, date("M j H:i:s") . "[] " . "PartnerID: " . $partnerid . " Phone: " . $phone . "\n");
Get parameters from the configuration file:
$lines = file("/usr/local/ispmgr/etc/sgtextmagic" . ($partnerid > 0 ? $partnerid : "") . ".conf", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$params = array();
foreach ($lines as $line_num => $line) {
$arr_key = "";
$arr_val = "";
list($arr_key, $arr_val) = explode(" ", $line, 2);
$params += array($arr_key => $arr_val);
}
$curl_client = curl_init("https://www.textmagic.com/app/api");
fwrite($log_file, date("M j H:i:s") . "[] " . curl_error($curl_client) . "\n");
Form the array to pass to the server:
$data = array("username" => $params["username"], "password" => $params["password"], "cmd" => "send",
"text" => $msg, "phone" => $phone, "unicode" => "0");
curl_setopt($curl_client, CURLOPT_SSL_VERIFYPEER, 0);
fwrite($log_file, date("M j H:i:s") . "[] " . curl_error($curl_client) . "\n");
curl_setopt($curl_client, CURLOPT_POST, 1);
fwrite($log_file, date("M j H:i:s") . "[] " . curl_error($curl_client) . "\n");
curl_setopt($curl_client, CURLOPT_POSTFIELDS, $data);
fwrite($log_file, date("M j H:i:s") . "[] " . curl_error($curl_client) . "\n");
$output = curl_exec($curl_client); //В случае успешного завершения запроса в $output помещается 1, в противном случае ничего.
fwrite($log_file, date("M j H:i:s") . "[] " . curl_error($curl_client) . "\n");
fwrite($log_file, date("M j H:i:s") . "[] " . $output . "\n");
curl_close($curl_client);
}
Error handler function:
function tmErrorHandler($errno, $errstr, $errfile, $errline) {
global $log_file;
fwrite($log_file, date("M j H:i:s") . "[] " . "Error [" . $errno . "] ErrMsg: " . $errstr . ". In file: " . $errfile . ". In line: " . $errline . "\n");
return true;
}
?>
Script handler written in Python 2.6
Specify a script handler and import the required modules:
#! /usr/bin/env python import sys, string, time, httplib, urllib, os, subprocess
Specify required functions
Define the output function into the log fie:
def log(msg):
log_file.write(time.strftime("%b %d %H:%M:%S[] ") + msg + "\n")
Define the function to output the script usage information:
def usage(): print "ISPsystem BILLmanager plugin v1.0" print "Text Magic integration plugin." print "Usage:" print "\tvalidate - print 'ok';" print "\ttune - no return value;" print "\ttype - return 'sms' as type of plugin;" print "\tcall 'country_code' 'phone_number' 'verification_code' 'lang' - execute plugin function.\n"
Define the function to send SMS:
def callapi(phone, code, lang="en"):
log("Start call api: phone = " + phone + ", code = " + code + ", lang = " + lang)
msg = "Your verification code is " + code
Open and read the configuration file:
config = open("/usr/local/ispmgr/etc/fptextmagic.conf", "r")
params = {}
for line in config.readlines():
line = string.strip(line, " \n")
kv = line.split(" ")
try:
params[kv[0]] = kv[1]
except IndexError:
params[kv[0]] = ""
config.close()
Form the array to send to the server. Use the object of the HTTPSConnection class to send the request:
params = urllib.urlencode({'username': params["username"], 'password': params["password"], 'cmd': "send", "text": "Your verification code is " + code, 'phone': phone, 'unicode': "0"})
headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"}
http_client = httplib.HTTPSConnection("www.textmagic.com");
http_client.request("POST", "/app/api", params, headers)
response = http_client.getresponse()
data = response.read()
log(str(response.status) + ":" + str(data))
Finish the module. If the MGR_LT_PID environment variable is specified, inform BILLmanager about the script completion:
if MGR_LT_PID == "None":
log("Standalong. No finish action")
else:
if response.status == 200:
subprocess.Popen(["/usr/local/ispmgr/sbin/mgrctl", "-m", "billmgr", "-o", "xml", "longtask.finish", "elid=" + str(os.getenv("MGR_LT_PID")), "status=ok"]);
else:
subprocess.Popen(["/usr/local/ispmgr/sbin/mgrctl", "-m", "billmgr", "-o", "xml", "longtask.finish", "elid=" + str(os.getenv("MGR_LT_PID")), "status=err", "errmsg='Error with cURL'"]);
Main script code
Open the log file to add messages:
log_file = open("/usr/local/ispmgr/var/fptextmagic.log", "a")
Redirect errors into the log file:
sys.stderr = log_file
Get the environment variable that contains the name of the PID-file of the longtask process.
MGR_LT_PID = str(os.getenv("MGR_LT_PID"))
Process the received command line parameters:
if len(sys.argv) < 2:
log("Too few parameters, print usage")
usage()
else:
Output to the validate command:
if sys.argv[1] == "validate": print "ok"
Output to the tune command:
elif sys.argv[1] == "tune": print ""
Output to the type command:
elif sys.argv[1] == "type": print "sms"
Process the sms send command (get the parameters and run the send function):
elif sys.argv[1] == "call":
if len(sys.argv) < 5 or len(sys.argv) > 6:
log("Too few or a lot parameters, print usage")
usage()
else:
phone = sys.argv[2] + sys.argv[3]
code = sys.argv[4]
if len(sys.argv) == 5:
callapi(phone, code)
elif len(sys.argv) == 6:
lang = sys.argv[5]
callapi(phone, code, lang)
else:
log("Too few or a lot parameters, print usage")
usage()
else:
usage()
Close the pointer to the log file:
log_file.close()
