На коленке накидал бот, который позволяет создавать выплаты через панель.
У нас нет публичного API, который позволяет создавать выплаты по соображениям безопасности. Ниже код, который имитирует запрос, словно он сделан через браузер.
Использование
/start
– пингует бота. Если бот ответил, значит установка правильная/setcookie $cookie
– сохраняет обязательный куки, без которого бот будет выдавать ошибку. Инструкция по получению выше/settoken $token
– также, как /setcookie/balance
– отображает баланс вашего аккаунта/payout $method $purse $sum
– запрашивает выплату на указанный реквизит.$method
может быть card или usdttrc (на момент редакции поста 03.10.2024)
Установка
- Установите на сервер ggram (скачайте и киньте в addons)
- По пути
addons/ggram-mod/lua/autorun/ggram-launcher.lua
скопируйте и вставьте код загрузчика из этой страницы - Создайте файл
addons/ggram-mod/lua/ggram/bots/gmdbot/_init.lua
и поместите в него код, который ниже - На первой строке укажите токен своего бота. Получить можно в Telegram: Contact @BotFather
- На 6й строке замените 123456 на свой telegram id. Получить можно в Telegram: Contact @jsonson_bot
- На этом этапе после перезагрузки сервера, у вас в боте должна работать команда
/start
. Если не работает, значит дальше пока не читайте, пока не разберетесь в проблеме - Если /start ответила “hello”, значит все хорошо. Теперь вам нужно вызвать команды
/setcookie
и/settoken
в боте. Информация ниже
Получаем значение для /setcookie
Можете либо извлечь значение куки без плагина или с плагином для браузера.
С плагином
Установите EditThisCookie, на странице выплат откройте окно расширения и скопируйте там это значение: скриншот
Без плагина
- Зайдите на сайт, сразу на страницу выплат.
- Откройте dev tools (F12)
- Обновите страницу и затем вот тут получите куки: скриншот. Копируйте значение после знака “равно” ( = ), но ДО точки с запятой ( ; )
Получаем значение для /settoken
- Открываем dev tools на странице выплат
- Меняем метод выплаты (например, с киви на карту или наоборот)
- Токен будет видно тут: скриншот
Код бота
Путь: addons/ggram-mod/lua/ggram/bots/gmdbot/_init.lua
(не забудьте установить ggram, как написано выше)
👉 Код (кликни сюда)
local bot = require("ggram")("your_bot_token")
require("ggram.polling").start(bot)
function bot.secureCommand(cmd, func)
return bot.command(cmd, function(ctx)
if ctx.from.id ~= 6014903768 then -- СЮДА НУЖНО ВСТАВИТЬ ТВОЙ TELEGRAM ID
-- if ctx.chat.id ~= 1234567 then -- Либо можно дать доступ целому админ чату
return ctx.reply.text("fak yu")
end
return func(ctx)
end)
end
bot.command("start", function(ctx) ctx.reply.text("hello") end)
-- либа, которая в гмоде сохраняет все в sv.db
local cookie = cookie or require("gmod.cookie")
local HTTP = HTTP or require("gmod.globals").HTTP
local BASE_URL = "https://gm-donate.net"
local function request(method, endpoint, parameters_, fSuccess, fError)
local session = cookie.GetString("gmd_session_cookie")
if not session then fError("Сначала нужно выполнить /setcookie") return end
if not cookie.GetString("gmd_post_token") then fError("Большинство запросов требуют /settoken") return end
HTTP({
method = method or "GET",
url = BASE_URL .. endpoint,
headers = {
Cookie = "laravel_session=" .. session,
Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
success = function(code, body, headers)
if body:find("cRay:") then fError("Запрос столкнулся с DDoS защитой. Напишите на @gm_donate") return end
if body:find("© Valve Corporation") then fError("Ошибка авторизации. Возможно, неправильный /setcookie") return end
if code == 419 then print("body", body) fError("Ошибка авторизации. Возможно, неправильный /settoken") return end
fSuccess(body, code, headers)
end,
failed = fError,
parameters = parameters_
})
end
local function get_balance(cb)
request("GET", "/panel/payouts", nil, function(body)
local bal_str = body:match("fa fa%-rub.-</span>.-([%d,%.]+).*</a>") -- 2,332.65
if not bal_str then print("gmd incorrect body", body) cb(false, "Ошибка парсинга баланса") return end
local bal_num = bal_str:gsub(",", "")
cb(true, tonumber(bal_num))
end, function(err) cb(false, err) end)
end
-- get_balance(print)
local function request_payout(sum, cb)
request("POST", "/panel/payouts/add", {
_token = cookie.GetString("gmd_post_token"),
sum = tostring(sum),
}, function(body, _, headers)
local redirect = (not not body:match("Redirecting to")) and headers.location
if redirect then
local string_PatternSafe = string.PatternSafe or require("gmod.string").PatternSafe
request("GET", headers.location:gsub( string_PatternSafe(BASE_URL),"" ), nil, function(cont)
local success = not not cont:match("Выплата запрошена")
cb(success, "При запросе выплаты на странице не найден искомый текст. Проверьте вручную, создалась ли выплата")
end, function(err2) cb(false, "Ошибка при редиректе после создания выплаты: " .. err2) end)
else
local success = not not cont:match("Выплата запрошена")
cb(success, "Проверьте вручную, создалась ли выплата. На странице не найден текст подтверждения")
end
end, function(err) cb(false, err) end)
end
-- request_payout(500, print)
-- 1 qiwi, 2 card
local function update_payout_method(sMethod, cb)
request("GET", "/panel/payouts/setPaymentMethod/" .. sMethod, {
_token = cookie.GetString("gmd_post_token"),
}, function(body, code)
if code ~= 200 then -- iMethod = 3 => 404
cb(false, "Статус код ожидался 200, но получен " .. code)
return
end
local bodyok = not not body:find("Метод выплат успешно изменен")
cb(bodyok, "На странице не найден текст подтверждения успешной смены реквизитов")
end, function(err) cb(false, err) end)
end
-- update_payout_method("usdttrc", function(ok) print("ok", ok) end)
local function update_purse(sMethod, purse, cb)
local params = {
_token = cookie.GetString("gmd_post_token"),
method = sMethod,
purse = purse,
}
request("POST", "/panel/payouts/save-settings", params, function(body, code, headers)
local redirect = (not not body:match("Redirecting to")) and headers.location
if redirect then -- #todo нет авторедиректов :(
local string_PatternSafe = string.PatternSafe or require("gmod.string").PatternSafe
request("GET", headers.location:gsub( string_PatternSafe(BASE_URL),"" ), nil, function(cont)
local success = not not cont:match("Реквизиты платежного метода изменены")
cb(success, "Проверьте вручную, изменились ли реквизиты и напишите в GMD support")
end, function(err2) cb(false, err2) end)
else
local success = not not cont:match("Реквизиты платежного метода изменены")
cb(success, "При попытке изменить реквизиты на странице не нашелся текст, подтверждающий успешность запроса")
end
end, function(err) cb(false, err) end)
end
-- update_purse("usdttrc", "TJL2bcC4o9pBH14EpHuoB5Jx8AUG4M628U", print)
-- update_purse("card", "1111222233334444", print)
-- Брать тут: https://file.def.pm/JYOF0cFb.jpg
bot.secureCommand("setcookie", function(ctx)
local cook = ctx.args()[1]
if not cook then
ctx.reply.text("Введите laravel_session куки вторым параметром.\n\n" ..
"Инструкция тут: https://forum.gm-donate.net/t/4396")
return
end
cookie.Set("gmd_session_cookie", cook)
ctx.reply.text("OK")
end)
-- Брать тут (из post запросов): https://file.def.pm/7d4c86D1.jpg
bot.secureCommand("settoken", function(ctx)
local token = ctx.args()[1]
if not token then
ctx.reply.text("Введите _token значение вторым параметром.\n\n" ..
"Инструкция тут: https://forum.gm-donate.net/t/4396")
return
end
if token:len() ~= 40 then
ctx.reply.text("Неправильная длина токена. Должно быть 40 символов")
return
end
cookie.Set("gmd_post_token", token)
ctx.reply.text("OK")
end)
bot.secureCommand("balance", function(ctx)
get_balance(function(ok, bal)
local str = ok and ("Баланс: " .. bal) or ("Ошибка запроса: " .. bal)
ctx.reply.text(str)
end)
end)
bot.secureCommand("payout", function(ctx)
local args = ctx.args()
local method, purse, sum = args[1], args[2], tonumber(args[3])
if not sum then
ctx.reply.markdown("Пример: `/payout $метод $реквизит $сумма`\n\n" ..
"Метод на момент написания кода (3 сент 2024) может быть `card`, либо `usdttrc`\n\n" ..
"Сумма может быть указана с копейками через точку, например 123.45")
return
end
update_payout_method(method, function(ok1, err)
if not ok1 then ctx.reply.text("Ошибка смены метода выплаты: " .. err) return end
update_purse(method, purse, function(ok2, err2)
if not ok2 then ctx.reply.text("Ошибка смены реквизитов: " .. err2) return end
request_payout(sum, function(ok3, err3)
ctx.reply.text(ok3 and "Запрос создан" or err3)
end)
end)
end)
end)
Примечания
- Код слишком хрупкий, может сломаться в любой момент, поскольку все данные просто парсит из html страницы-ответа, которая в будущем может меняться. Тем не менее, я готов делать фиксы, если это будет востребованно в этой теме
- Здесь нет проверки статуса выплаты, это сильно усложнило бы код, тем не менее такую функцию можно доделать самостоятельно (после создания выплаты парсите таблицу выплат и проверяете статус раз в пару минут)
- Код будет работать как на Garry’s Mod, так и на чистом Lua (за пределами гаррисмод). Тестировалось как раз в обычном Lua. Вот здесь я немного писал об этой библиотеке для ботов
- Мы не принимаем никаких жалоб на то, что у вас украли деньги. Вы сами в ответе за секретные данные и сами отвечаете за их защиту. Если вдруг у вас украдут код сервера, а с ним и сделают выплаты – мы не поможем. Могу лишь порекомендовать не хранить секретные данные в lua файлах или делать выплаты вручную
- Время от времени куки и токен может потребоваться обновлять. Я не могу точно сказать, насколько часто это нужно будет делать, но полагаю, что не очень часто