Создание дополнительных модулей защиты от мошенничества
Материал из ISPWiki
Архитектура BILLmanager позволяет добавлять к системе собственные модули-обработчики. Структура модуля защиты от мошенничества состоит из двух файлов:
- XML файл описания интерфейса настройки параметров соединения на стороне провайдера с именем billmgr_mod_xxx.xml, где xxx любая уникальная разрешенная последовательность символов. Файл должен располагаться в папке {путь к папке установки}/etc/ и обязательно должен быть в кодировке UTF-8.
- Бинарный или текстовый (в зависимости от языка реализации) файл модуля обработчика. Файл должен располагаться в каталоге /usr/local/ispmgr/sbin/, имя файла должно начинаться с fp.
Содержание |
Структура файла XML
Документ XML состоит из двух частей:
- Описание полей формы параметров
- Локализованные подписи к полям формы
<?xml version="1.0" encoding="UTF-8"?> <mgrdata> <metadata name="fraudparam_xxx" type="form"> <!-- xxx - имя вашего модуля без '''fp''' --> <form> <!--Поля конфигурации необходимые для работы вашего модуля. Отображаются при вводе параметров модуля--> <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 - имя вашего модуля без '''fp'''. Раздел нужен, если планируется использовать модуль в качестве СМС шлюза --> <form> <!--Поля конфигурации необходимые для работы вашего модуля. Отображаются при вводе параметров модуля--> <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"> <!-- В документа XML может быть описано несколько языков, для правильной работы наличие английского языка обязательно --> <messages name="fraudconf"> <msg name="xxx">XXX</msg> <!-- xxx - имя вашего модуля без '''fp''', XXX - отображаемое имя модуля в списке выбора --> </messages> <messages name="fraudparam_xxx"> <!-- xxx - имя вашего модуля без '''fp''' --> <msg name="title">Title</msg> <!-- Заголовок окна ввода параметров --> <msg name="field_name_1">field name 1</msg> <!-- Подпись поля в окне настроек модуля --> <msg name="hint_field_name_1">hint field name 1</msg> <!-- Подсказка отображаемая при наведении на подпись поля --> <!--...--> <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 - имя вашего модуля без '''fp'''. Раздел нужен, если планируется использовать модуль в качестве СМС шлюза --> <msg name="title">Title</msg> <!-- Заголовок окна ввода параметров --> <msg name="field_name_1">field name 1</msg> <!-- Подпись поля в окне настроек модуля --> <msg name="hint_field_name_1">hint field name 1</msg> <!-- Подсказка отображаемая при наведении на подпись поля --> <!--...--> <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"> <!--Те же параметры для другого языка--> </lang> </mgrdata>
Структура модуля
При работе BILLmanager обращается к файлу модуля передавая ему необходимые данные через параметры командной строки. Реализация модуля обработчика должна предусматривать обязательную обработку параметров командной строки и реализовывать соответствующую логику реакции на передаваемые команды.
До версии 4.0.61
Параметры конфигурации модуля сохраняются в файл {путь к папке установки}/etc/fpxxx.conf (sgxxx{ID партнера}.conf - для настроек СМС шлюза), где xxx - имя модуля, в формате: <имя параметра> <значение>. Каждый параметр записан с новой строки.
Начиная с версии 4.0.61
Параметры конфигурации модуля сохраняются в базе данных, таблица support_gate, поле xmldata, в формате XML. Каждый параметр представлен нодой XML документа.
Принимаемые команды и параметры
- features - в стандартный поток необходимо передать список поддерживаемых функций: fraud и/или gate, например: "fraud gate".
- validate - необходимо проверить данные и передать 'ok' в стандартный поток вывода или ошибку, если необходимо.
- tune - при необходимости в ответ на эту команду можно передать в стандартный поток вывода XML документ описания интерфейса.
- type - необходимо передать в стандартный поток вывода тип модуля: 'sms', если будет производится отправка SMS сообщения, или 'call', если будет производится звонок.
- sendsms - команда отправки СМС сообщения, принимает параметры: partnerid' phone' и текст сообщения через стандартный поток ввода. Здесь 'partnerid' - идентификатор учетной записи партнера, если отправка СМС производится клиенту партнера, 'phone' - номер телефона, на который производится отправка сообщения. По окончанию отправки в стандартный поток вывода нужно передать "OK", если отправка произведена успешно, и "ERROR", если отправка завершилась с ошибкой.
- call - вызов обработчика отправки SMS или совершения звонка, полная версия вызова выглядит как fpxxx call ccode phone code lang, где call - управляющая команда, ccode - код страны в номере телефона (первые поле при прохождении процедуры проверки телефона), phone - номер телефона, code - проверочный код, lang - код основного языка пользователя.
По выполнению команды call модуль должен сообщить BILLmanager о своем завершении:
- В случае успешного завершения необходимо вызвать команду '{путь к папке установки}/sbin/mgrctl -m billmgr -o xml longtask.finish elid=(PID файл запуска) status=ok'
- В ином случае необходимо вызвать команду '{путь к папке установки}/sbin/mgrctl -m billmgr -o xml longtask.finish elid=(PID файл запуска) status=err errmsg=(текст сообщения об ошибке)'
Подробнее об этом в статье про LongTask
Пример модуля
Рассмотрим создание скрипта модуля на примере подключения к API TextMagic (приведенный ниже текст XML и скрипта обработчика является лишь примером, и не может быть использован в рабочей среде без переработки).
XML документ
Пример XML документа:
<?xml version="1.0" encoding="UTF-8"?> <mgrdata> <metadata name="fraudparam_textmagic" type="form"> <form>
Далее идут параметры конфигурации модуля:
<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>
Далее идут параметры конфигурации модуля для настройки СМС шлюза:
<field name="username"> <input type="text" name="username" empty="no"/> </field> <field name="password"> <input type="text" name="password" empty="no"/> </field> </form> </metadata>
Описание английской локализации формы ввода параметров:
<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>
Описание русскоязычной локализации формы ввода параметров:
<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>
Скрипт обработчик
Пример скрипта обработчика на PHP
#!/usr/bin/php <?php
Устанавливаем свой обработчик ошибок для записи их в лог файл вместо передачи в стандартный поток вывода:
set_error_handler("tmErrorHandler");
Открываем log файл:
$log_file = fopen("/usr/local/ispmgr/var/fptextmagic.log", "a");
fwrite($log_file, "=======".date("M j H:i:s") . "[] " ."=======\n");
Записываем принятые параметры в log файл:
foreach($argv as $line_num => $line) {
fwrite($log_file, date("M j H:i:s") . "[] " . $line_num.":".$line."\n");
}
Обработка принятых параметров (первым параметром принимается имя запускаемого файла), если количество принятых параметров меньше двух выводим информацию по использованию модуля, для команды call передается 3 или 4 параметра, значит модуль должен принять 4 или 5 параметров:
if ($argc<2) {
usage();
} else {
switch($argv[1]) {
Возвращаем 'ok':
case "features": echo "fraud gate"; break; case "validate": echo "ok"; break; case "tune": break;
Возвращаем тип модуля sms:
case "type": echo "sms"; break;
Вызываем обработчик отправки 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);
Функция вывода информации по использованию модуля:
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 для защиты от мошенничества:
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;
Считываем параметры из файла конфигурации:
$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");
Формируем массив передаваемых на сервер параметров:
$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");
Завершаем работу модуля:
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);
}
Функция отправки СМС в качестве шлюза:
function callgate($partnerid, $phone, $msg) {
global $log_file;
fwrite($log_file, date("M j H:i:s") . "[] " . "PartnerID: " . $partnerid . " Phone: " . $phone . "\n");
Считываем параметры из файла конфигурации:
$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");
Формируем массив передаваемых на сервер параметров:
$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);
}
Функция обработчика ошибок:
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;
}
?>
Пример скрипта обработчика на Python 2.6
Указываем обработчик скрипта и импортируем необходимые модули:
#! /usr/bin/env python import sys, string, time, httplib, urllib, os, subprocess
Определяем необходимые функции
Определяем функцию вывода в лог файл:
def log(msg):
log_file.write(time.strftime("%b %d %H:%M:%S[] ") + msg + "\n")
Определяем функцию вывода информации по использованию скрипта:
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"
Определяем функцию обработки отправки SMS сообщения:
def callapi(phone, code, lang="en"):
log("Start call api: phone = " + phone + ", code = " + code + ", lang = " + lang)
msg = "Your verification code is " + code
Открываем и считываем файл конфигурации:
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()
Формируем массив передаваемых на сервер параметров и используя объект класса HTTPSConnection отправляем запрос на сервер:
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))
Завершаем работу модуля, если определена переменная окружения MGR_LT_PID сообщаем BILLmanager о статусе завершения работы скрипта:
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'"]);
Основной код скрипта
Открываем файл лога для добавления сообщений:
log_file = open("/usr/local/ispmgr/var/fptextmagic.log", "a")
Перенаправляем поток ошибок в файл лога:
sys.stderr = log_file
Считываем переменную окружения содержащую имя PID файла longtask процесса
MGR_LT_PID = str(os.getenv("MGR_LT_PID"))
Обрабатываем принятые параметры командной строки:
if len(sys.argv) < 2:
log("Too few parameters, print usage")
usage()
else:
Выводим ответ на команду validate:
if sys.argv[1] == "validate": print "ok"
Выводим ответ на команду tune:
elif sys.argv[1] == "tune": print ""
Выводим ответ на команду type:
elif sys.argv[1] == "type": print "sms"
Обрабатываем команду отправки сообщения (считываем параметры и запускаем функцию отправки):
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()
Закрываем указатель на лог файл:
log_file.close()
