Авторизации XenForo через сервер

Сообщения
673
Реакции
242
Помог
11 раз(а)
Добрый вечер

Для тех кто знаком и "умеет читать" форум на движке XenForo

имеется запрос:
Код:
    new query[QUERY_LENGTH], que_len;

    que_len += formatex(query[que_len],charsmax(query) - que_len,  "SELECT `username`, `data` FROM `xf_users`, xf_user_authenticate WHERE `username` = '%s' AND `data` = '%s'", Login, Password);
    
    new sData[EXT_DATA_STRUCT];
    
    sData[EXT_DATA__SQL] = SQL_LOADPLAYERDB;
    sData[EXT_DATA__INDEX] = id;
    sData[EXT_DATA__USERID] = get_user_userid(id);
    
    copy(sData[EXT_DATA__LOGIN], 31, Login);
    copy(sData[EXT_DATA__PASS], 31, Password);

    mysql_query(g_Connection,  "selectQueryHandler",query, sData, sizeof(sData));
каким образом шифруется пароли на форуме, читал что есть соль, на котором у каждого пользователя рандомиться

как говорит интернет пассы шифруется вот таким образом:

Код:
UPDATE xf_user_authenticate
SET data = BINARY
    CONCAT(
        CONCAT(
            CONCAT('a:3:{s:4:"hash";s:40:"', SHA1(CONCAT(SHA1('password'), SHA1('salt')))),
            CONCAT('";s:4:"salt";s:40:"', SHA1('salt'))
        ),
        '";s:8:"hashFunc";s:4:"sha1";}'
    ),
scheme_class = 'XenForo_Authentication_Core'
WHERE user_id = 8;
Где -
password и есть пароль

встал в ступор на получение соли, спасибо за помощь
 
Сообщения
207
Реакции
420
Помог
10 раз(а)
Сообщения
207
Реакции
420
Помог
10 раз(а)
Дам более развёрнутый ответ, на будущее.
  1. Заходим в src/config.php, убеждаемся, что там нет строки, выключающей API ($config['enableApi'] = false).
  2. В админке находим API-ключи (НастройкиAPI-ключи | SetupAPI keys) - /admin.php?api-keys/
  3. Создаём новый ключ типа Super user key с одним единственным скопом прав: auth.
    1578129371549.png
  4. Копируем выданный нам ключ. Его нужно держать в тайне, и не показывать никому.
  5. Смотрим в документацию к методу auth, и видим, что нужно передавать обязательно login и password. Опционально можно ещё передать IP-адрес, откуда происходит авторизация, чтобы юзера могло забанить за брут.
  6. Реализуем плагин. Ниже прикладываю пример для REST in Pawn и SourceMod (CS:S, CS:GO, TF2, DoD:S, Fistful of Frags и многие другие...).
C++:
/**
 * Плагин-пример проверки пары "логин-пароль".
 * Реализован для топика #8875 на Dev-CS.
 *
 * Для работоспособности, понадобится установить
 * аддон-расширение, реализующее поддержку тел
 * запросов в формате JSON.
 * @see https://board.kruzya.me/resource/28/
 * @see https://xenforo.info/resources/8260/
 *
 * @use sourcemod
 * @use ripext
 */

#include <sourcemod>
#include <ripext>

// если ЧПУ не активен, ссылка должна быть вида: baseURL/index.php?api
// обязательно без слеша в конце! его добавляет само расширение всегда!
//
// P.S.: Такие параметры в идеале надо в конфиг вытаскивать, а не хардкодить.
stock const char    g_szApiEndpoint[]    = "https://localhost:33000/api";
stock const char    g_szApiKey[]        = "ABCDEF90GBNebBsDXqZtnv_UO85Q1Ub7";

HTTPClient    g_hClient;

public void OnPluginStart()
{
    g_hClient = new HTTPClient(g_szApiEndpoint);
    g_hClient.SetHeader("XF-Api-Key", g_szApiKey);
    g_hClient.SetHeader("User-Agent", "Source Dedicated Server (RiP)");

    RegConsoleCmd("xf_login", OnLoginCmd);
}

public Action OnLoginCmd(int iClient, int iArgC)
{
    if (iArgC != 2)
    {
        ReplyToCommand(iClient, "[XF] Usage: xf_login <username/email> <password>");
        return Plugin_Handled;
    }

    bool bUseIP = (iClient != 0); // передаём IP-адрес только если это не серверная консоль
    char szLogin[128];
    char szPassword[128];

    GetCmdArg(1, szLogin, sizeof(szLogin));
    GetCmdArg(2, szPassword, sizeof(szPassword));

    JSONObject hRequest = new JSONObject();
    hRequest.SetString("login", szLogin);
    hRequest.SetString("password", szPassword);

    // ограничение по IP-адресу может быть полезно,
    // чтобы кто-то из игры не перебирал пароль.
    // при этом, перебор для пользователя сломается
    // и напрямую через сам форум.
    if (bUseIP)
    {
        char szIP[32];
        if (GetClientIP(iClient, szIP, sizeof(szIP)))
        {
            hRequest.SetString("limit_ip", szIP);
        }
    }

    DataPack hPack = new DataPack();
    hPack.WriteCell(UTIL_SafeUserId(iClient));
    hPack.WriteCell(bUseIP);
    hPack.WriteCell(GetCmdReplySource());

    g_hClient.Post("auth", hRequest, OnAuthRequestFinished, hPack);
    ReplyToCommand(iClient, "[XF] Waiting response from API...");
    return Plugin_Handled;
}

public void OnAuthRequestFinished(HTTPResponse hResponse, DataPack hPack, const char[] szError)
{
    hPack.Reset();
    int iClient = UTIL_SafeUnUserId(hPack.ReadCell());
    bool bIsClient = hPack.ReadCell();
    ReplySource eSource = hPack.ReadCell();
    hPack.Close();

    if (iClient == 0 && bIsClient)
    {
        // client disconnected.
        return;
    }

    if (!hResponse || !hResponse.Data)
    {
        LogError("Request failure: %s", szError);
        UTIL_ReplyToCommand(iClient, eSource, "[XF] API responsed by failure. Please, try again later.");
        return;
    }

    JSONObject hResponseRoot = view_as<JSONObject>(hResponse.Data);
    if (hResponseRoot.HasKey("errors"))
    {
        JSONArray hErrors = view_as<JSONArray>(hResponseRoot.Get("errors"));
        int iErrorCount = hErrors.Length;

        JSONObject hError;
        char szErrorCode[80];
        for (int iErrorId = 0; iErrorId < iErrorCount; ++iErrorId)
        {
            hError = view_as<JSONObject>(hErrors.Get(iErrorId));
            hError.GetString("code", szErrorCode, sizeof(szErrorCode));
            hError.Close();

            if (strcmp(szErrorCode, "incorrect_password") == 0 || strcmp(szErrorCode, "requested_user_x_not_found") == 0)
            {
                UTIL_ReplyToCommand(iClient, eSource, "[XF] You entered an incorrect password or login. Please, try again.");
            }
            else if (strcmp(szErrorCode, "your_account_has_temporarily_been_locked_due_to_failed_login_attempts") == 0)
            {
                UTIL_ReplyToCommand(iClient, eSource, "[XF] You entered an incorrect password too many times.");
                UTIL_ReplyToCommand(iClient, eSource, "[XF] Account locked.");
            }
        }

        hErrors.Close();
        return;
    }

    // пользователь успешно авторизовался. выведем его никнейм и тайтл.
    // всё, что доступно - можно глянуть здесь:
    // https://xenforo.com/community/pages/api-endpoints/#type_User
    char szUsername[64];
    char szUserTitle[64];
    JSONObject hUser = view_as<JSONObject>(hResponseRoot.Get("user"));
    hUser.GetString("username", szUsername, sizeof(szUsername));
    hUser.GetString("user_title", szUserTitle, sizeof(szUserTitle));

    UTIL_ReplyToCommand(iClient, eSource, "[XF] You are successfully authorized!");
    UTIL_ReplyToCommand(iClient, eSource, "[XF] Welcome, %s", szUsername);
    UTIL_ReplyToCommand(iClient, eSource, "[XF] Your title: %s", szUserTitle);
    hUser.Close();
}

stock void UTIL_ReplyToCommand(int iClient, ReplySource eSource, const char[] szFormatString, any ...)
{
    char szMessage[256];
    SetGlobalTransTarget(iClient);
    VFormat(szMessage, sizeof(szMessage), szFormatString, 4);

    ReplySource eOldSource = SetCmdReplySource(eSource);
    ReplyToCommand(iClient, "%s", szMessage);

    if (eSource != eOldSource)
    {
        SetCmdReplySource(eOldSource);
    }
}

stock int UTIL_SafeUserId(int iClient)
{
    if (iClient > 0)
    {
        iClient = GetClientUserId(iClient);
    }

    return iClient;
}

stock int UTIL_SafeUnUserId(int iUserId)
{
    if (iUserId > 0)
    {
        iUserId = GetClientOfUserId(iUserId);
    }

    return iUserId;
}
20328
 
Сообщения
673
Реакции
242
Помог
11 раз(а)
Спасибо, посижу посмотрю))

знать бы что за что отвечает сурс к amxx) нативы какие-то непонятны)
 
Сообщения
207
Реакции
420
Помог
10 раз(а)
Тут главное понять, как сам запрос к веб серверу должен выглядеть.
Может fantom подскажет, как оно же будет в грипе смотреться
 

Пользователи, просматривающие эту тему

Сейчас на форуме нет ни одного пользователя.
Сверху Снизу