[Include] safeDialogs - Complete protection against spoofed dialog data!
#1

safeDialogs
Complete protection against spoofed dialog data (id, list-item and input-text)
Version - 1.0.3 (use v1.0.2 until a stable version is released)
Last update - 8th of February, 2017
NOTE : I've been inactive since a while. I'll be working on the include after settling few things.
Introduction
safeDialogs detects and prevents players sending falsified dialog responses that includes wrong dialog ID, invalid list-item or fake input-text (list-item string). Faking list-item or item string can lead to many risks of player breaking server security. It can also lead to crashes where listitem used as array index goes out of bounds. However, this include ensures that everything's safe and filtered. This include triggers a callback on player sending spoofed dialog response.
How's this different from others?
I've never seen any anti-cheat or dialog include that provides protection over list items and over sending fake inputtext data for list type dialogs. This topic is what that has inspired me to create such an include to provide complete protection over dialog responses.

Exploit Protection
Spoofed dialog ids Yes
Spoofed dialog list-items Yes
Spoofed dialog list-item inputtext Yes
Filtering user's inputtext Yes
Callbacks and Functions
Callback
pawn Code:
public OnDialogSpoof(playerid, spooftype) {

    return 0; //Return 0 to block spoofed data!
}
Parameters:
playerid - The player who sent spoofed data.
spooftype - Spoof type.

Spoof types:
DIALOG_SPOOFTYPE_DIALOG_ID - If dialog ID is spoofed.
DIALOG_SPOOFTYPE_LIST_ITEM - If dialog listitem is spoofed.
DIALOG_SPOOFTYPE_INPUT_TEXT - If dialog inputtext (for lists) is spoofed.

Enumerator
pawn Code:
enum {

    DIALOG_SPOOFTYPE_DIALOG_ID,
    DIALOG_SPOOFTYPE_LIST_ITEM,
    DIALOG_SPOOFTYPE_INPUT_TEXT
}
Functions - These functions can only be used under OnDialogResponse and OnDialogSpoof. Once any of these callbacks are over, they'll return their default values only.

pawn Code:
native GetPlayerDialog(playerid); //Returns the current dialog ID of player.
native GetPlayerDialogStyle(playerid); //Returns the current dialog style of player. (255 if invalid)
native GetPlayerDialogInfo(playerid, dest[], size = sizeof(dest)); //Stores the dialog info to "dest" array.
native GetPlayerDialogItem(playerid, listitem, dest[], bool:filter = false, size = sizeof(dest)); //Stores the dialog's list-item string to "dest" array. View change-logs (v1.0.3) below to know more.
Important Notes
• This include must be included on every scripts that uses dialog features.
• This include must be included after a_samp to ensure any other includes using dialog features are also protected. If you're having "fixes.inc" - include this after fixes.inc to avoid the user errors by fixes.inc.
• If you're using easyDialogs, yes, this can be integrated along with it. But include safeDialogs before easyDialogs.
• If your script is having a list-item of length greater than 256, edit MAX_DIALOG_LISTITEM_LEN. Or simply do this:
pawn Code:
//These defines are optional. If you haven't defined, script will use it's default values.

//Before including safeDialogs
#define MAX_DIALOG_LISTITEM_LEN 300

//You can also define MAX_DIALOG_STRING (not greater than 2048 since that's a limitation on SA-MP)
#define MAX_DIALOG_STRING 2000

#include <a_samp>
#include <safeDialogs>
Usage
Using this include is very easy! A small example is given below.
pawn Code:
#include <a_samp>
#include <safeDialogs>

public OnDialogSpoof(playerid, spooftype) {

    //Player is spoofing dialog!
    Kick(playerid); //Kick the player.
    return 0; //Block the spoofed data by returning 0. Returning other values will accept spoofed data which isn't recommended.
}
Changelogs

safeDialogs - v1.0.3 (optional / minor update):
- Added a static-global array to handle huge strings, thereby freeing more heap space. If you were facing any heap space related warning after including safeDialogs earlier, it should be fixed now.

- Improved list-item filtering. There used to be a confusion for non-hex codes between curly braces in list-item string, no more now though!

- Added new function : GetPlayerDialogItem - It stores the list-item string/data into destination. Using this function, you don't have to rely on inputtext for list-type dialogs to get their string data. In cases of DIALOG_STYLE_TABLIST or DIALOG_STYLE_TABLIST_HEADERS - it stores the complete list-item data.
pawn Code:
GetPlayerDialogItem(playerid, listitem, dest[], bool:filter = false, size = sizeof(dest));

playerid - The player to obtain data from.
listitem - The listitem of which data/string has to be obtained.
dest[] - Array to store string/data.
filter = false - Whether to filter the contents in a list-item. If filter is set to true,
                   it will automatically remove color embedding and make it look like
                   how it's shown to clients / players.
                   If filter is set to false (by default it'
s false), it will show the raw data
                   which may or may not include color embedding, depending on how the
                   code is.
size = sizeof(dest) - The size of destination array.
To know more about this function and how it outputs - http://forum.sa-mp.com/showpost.php?...0&postcount=17

- Fixed functions : Functions from safeDialogs can now be used under OnDialogResponse and OnDialogSpoof.

- Include initialization won't call OnPlayerConnect completely anymore, instead it only resets necessary variables. This also means that "_ALS_" hook errors upon including certain libraries along with safeDialogs, are fixed.
safeDialogs - v1.0.2:
- Fixed false triggers for dialogs using color embedding. Thanks to GoldenLion for reporting!
- Include is now completely stand-alone. It no longer requires script_compatibility include since it had a problem with users using YSI.
safeDialogs - v1.0.1:
- Fixed false triggers for DIALOG_STYLE_TABLIST and DIALOG_STYLE_TABLIST_HEADERS. Thanks to GoldenLion for reporting!
safeDialogs - v1.0:
- Initial release.
Download

Github : https://github.com/Lordzy/safeDialogs
Raw source : https://raw.githubusercontent.com/Lo...afeDialogs.inc
Reply
#2

Exacly what I need, I have been struggling months ago to find something similar, good job mate!
Reply
#3

Awesome lordzy will try and let u know if there will be any issue +rep
Reply
#4

Seems to be nice, but when I tried it a few minutes ago OnDialogSpoof got called for no reason when I used DIALOG_STYLE_TABLIST_HEADERS.
Reply
#5

Quote:
Originally Posted by GoldenLion
View Post
Seems to be nice, but when I tried it a few minutes ago OnDialogSpoof got called for no reason when I used DIALOG_STYLE_TABLIST_HEADERS.
Can you please post the code?
Reply
#6

Quote:
Originally Posted by Lordzy
View Post
Can you please post the code?
The code doesn't matter, but the spoof type was DIALOG_SPOOFTYPE_INPUT_TEXT. The problem must be that the inputtext at OnDialogResponse for DIALOG_STYLE_TABLIST_HEADERS and DIALOG_STYLE_TABLIST_HEADERS is the text before the first '\t' as far as I know so for example let's say there is "Item1\tItem2\n" in the dialog, but the inputtext at OnPlayerDialogResponse is just "Item1" (or "Item1\t"), not "Item1\tItem2\n" so the include thinks the inputtext is spoofed.
Reply
#7

Quote:
Originally Posted by GoldenLion
View Post
The code doesn't matter, but the spoof type was DIALOG_SPOOFTYPE_INPUT_TEXT. The problem must be that the inputtext at OnDialogResponse for DIALOG_STYLE_TABLIST_HEADERS and DIALOG_STYLE_TABLIST_HEADERS is the text before the first '\t' as far as I know so for example let's say there is "Item1\tItem2\n" in the dialog, but the inputtext at OnPlayerDialogResponse is just "Item1" (or "Item1\t"), not "Item1\tItem2\n" so the include thinks the inputtext is spoofed.
Thanks for reporting, it has been fixed! I suggest everyone to re-download the latest commit.
Reply
#8

Ah, one of my half-way finished projects. Great to see one released as I never got around finishing mine.

Here's a suggestion for you, thats a huge array sitting somewhere unused until they use dialogs, so use PVars instead.
Reply
#9

Quote:
Originally Posted by Naruto_Emilio
View Post
Exacly what I need, I have been struggling months ago to find something similar, good job mate!
You should also know that another solution was changing to selectable textdraws.

On topic: I really hope this really works as there have previously been such releases, however, they haven't prevented the user from not modifying the listitem's text.
Reply
#10

Quote:
Originally Posted by Lordzy
View Post
Thanks for reporting, it has been fixed! I suggest everyone to re-download the latest commit.
The bug is still there. I think it's not possible to fix it as it's impossible to get the whole inputtext.
Reply
#11

Quote:
Originally Posted by PrO.GameR
View Post
Ah, one of my half-way finished projects. Great to see one released as I never got around finishing mine.

Here's a suggestion for you, thats a huge array sitting somewhere unused until they use dialogs, so use PVars instead.
I didn't consider using PVars because of their slow performance and also I saw no use of having dialog-string over other scripts. I know there are bulk of data unused which is why I've considered using packed strings. I'll be running few benchmarks and switch over PVars if needed. Thanks for suggesting!

Quote:
Originally Posted by Swedky
View Post
Another amazing release! Good job over there Lordz
I'll be looking at the code and tell you if find some bug :P
I'd really be grateful if you find and report them because I haven't tested this include VERY well.

Quote:
Originally Posted by GoldenLion
View Post
The bug is still there. I think it's not possible to fix it as it's impossible to get the whole inputtext.
It'd be really helpful if you're pointing out how or what code brings in the false call of OnDialogSpoof. Because I haven't really worked with dialogs since the release of SA-MP 0.3.7. I've noticed now that false calls would be given only if a header type dialog is shown as empty. I really don't know why'd anyone show an empty header dialog but I assume in situations to show an empty inventory, that might be used. ()

A minor update has been done to this include to prevent false alarms on empty header dialog. This is the code I used right now for testing:
pawn Code:
//testing safeDialogs
#define FILTERSCRIPT

#include <a_samp>
#include <safeDialogs>
#include <zcmd>

static const dialogSpoofReasons[][] = {

    {"spoofing dialog ID"},
    {"spoofing list-item"},
    {"spoofing input-text"}
};


public OnDialogSpoof(playerid, spooftype) {

    new
        tempString[144],
        tempName[MAX_PLAYER_NAME + 1]
    ;

    GetPlayerName(playerid, tempName, sizeof(tempName));
    format(tempString, sizeof(tempString), "%s (ID:%d) has been caught for %s",
        tempName, playerid, dialogSpoofReasons[spooftype]);
       
    SendClientMessageToAll(-1, tempString);
   
    print("\a"); //Beep sound.
    print(tempString);
   
    return 0;
}

CMD:showdialog(playerid, params[]) {

    if(isnull(params))
        return SendClientMessage(playerid, 0xFF0000FF, "USAGE : /showdialog [type]");
       
    if(!strcmp(params, "list", true)) {
   
        ShowPlayerDialog(playerid, 1, DIALOG_STYLE_LIST, "DIALOG_STYLE_LIST",
        "Item1\nItem2\nItem3\nItem4", "Select", "Close");
    }
    else if(!strcmp(params, "msgbox", true)) {
   
        ShowPlayerDialog(playerid, 1, DIALOG_STYLE_MSGBOX, "DIALOG_STYLE_MSGBOX",
        "Item1\nItem2\nItem3\nItem4", "Select", "Close");
    }
    else if(!strcmp(params, "header", true)) {
   
        ShowPlayerDialog(playerid, 1, DIALOG_STYLE_TABLIST_HEADERS,
        "DIALOG_STYLE_TABLIST_HEADERS",
        "Item\tIndex\n\
        Item\t1\n\
        Stuff\t2\n\
        Other\t3"
, "Select", "Close");
        /*ShowPlayerDialog(playerid, 1, DIALOG_STYLE_TABLIST_HEADERS,
        "DIALOG_STYLE_TABLIST_HEADERS",
        "Item\tIndex\n", "Select", "Close");*/

    }
    else if(!strcmp(params, "tablist", true)) {
   
        ShowPlayerDialog(playerid, 1, DIALOG_STYLE_TABLIST,
        "DIALOG_STYLE_TABLIST",
        "Item\t1\n\
        Stuff\t2\n\
        Other\t3"
, "Select", "Close");
    }
    else if(!strcmp(params, "input", true)) {
   
        ShowPlayerDialog(playerid, 1, DIALOG_STYLE_INPUT, "DIALOG_STYLE_INPUT",
        "Input some stuff", "Select", "Close");
    }
    return 1;
}
Please re-download the latest commit if you're facing issue with empty header dialogs.
Reply
#12

I printed out the stuff to show you what's up.
This is what the dialog looks like in-game: https://gyazo.com/8f43f40824ac5c85f6e216325d005fcb
This is what it printed when I clicked on the mask:
Code:
inputtext: Mask
tempDListString: {FFFFFF}Mask	  1	0.10 lbs
As you can see the inputtext is the text before the first '\t' and tempDListString is the whole inputtext so strcmp always fails. Also inputtext doesn't include the color so it will call OnDialogSpoof whenever you use a color in any dialog.
Reply
#13

Quote:
Originally Posted by GoldenLion
View Post
I printed out the stuff to show you what's up.
This is what the dialog looks like in-game: https://gyazo.com/8f43f40824ac5c85f6e216325d005fcb
This is what it printed when I clicked on the mask:
Code:
inputtext: Mask
tempDListString: {FFFFFF}Mask	  1	0.10 lbs
As you can see the inputtext is the text before the first '\t' and tempDListString is the whole inputtext so strcmp always fails. Also inputtext doesn't include the color so it will call OnDialogSpoof whenever you use a color in any dialog.
The first issue you stated was fixed on v1.0.1 of this include because strings would be compared up to the length of inputtext only. Color embedding is something I've forgot - fixed now!

v1.0.2 has been released!
- Fixes false calls on dialog lists having color embedding.
- Include is completely stand-alone now. It requires no script_compatibility include since it was a problem for users using YSI.

Please re-download the latest commit of this include. If you find any more issues, please post on this topic as it'd really be helpful.
Reply
#14

It's really a shame that we can't use the whole inputtext line in tablists.
Good job on fixing everything I was concerned with, adding it to my server.
Reply
#15

EDIT : Never mind this function - v1.0.3 supports a better version of this function.

Quote:
Originally Posted by PrO.GameR
View Post
It's really a shame that we can't use the whole inputtext line in tablists.
I wrote a function that can get you the whole inputtext line for tablists and header using this include. I couldn't test this since I'm not at home these days, typed these on my mobile. I'd be grateful if someone tests to see if it works.
pawn Code:
#include <a_samp>
#include <safeDialogs>

GetPlayerDialogItem(playerid, listitem, dest[], size = sizeof(dest)) {

    new
        initPoint,
        endPoint,
        tempCounts,
        dStr[MAX_DIALOG_STRING],
        dLen
    ;

    tempCounts = (GetPlayerDialogStyle(playerid) == DIALOG_STYLE_TABLIST_HEADERS) ? -2 : -1;
    GetPlayerDialogInfo(playerid, dStr, sizeof(dStr));
    dLen = strlen(dStr);

    for(endPoint = 0; endPoint < dLen; endPoint++) {

        if(dStr[endPoint] == '\n') {

            if(++tempCounts == listitem)
                break;
            initPoint = endPoint;
        }
    }
    if(initPoint != 0)
        initPoint++;

    strmid(dest, dStr, initPoint, endPoint, size));
    return 1;
}
Usage:
pawn Code:
public OnDialogResponse(...) {

    if(dialogid == sometablistID) {

        new
            listStr[256];
       GetPlayerDialogItem(playerid, listitem, listStr);
       //listStr now contains the item's string regardless of player's input.
      //It's the raw data which even includes color embedding.
Reply
#16

safeDialogs - v1.0.3 (optional/minor update) released!

- Added a static-global array to handle huge strings, thereby freeing more heap space. If you were facing any heap space related warning after including safeDialogs earlier, it should be fixed now.
- Improved list-item filtering. There used to be a confusion for non-hex codes between curly braces in list-item string, no more now though!
- Added new function : GetPlayerDialogItem - It stores the list-item string/data into destination. Using this function, you don't have to rely on inputtext for list-type dialogs to get their string data. In cases of DIALOG_STYLE_TABLIST or DIALOG_STYLE_TABLIST_HEADERS - it stores the complete list-item data.
pawn Code:
GetPlayerDialogItem(playerid, listitem, dest[], bool:filter = false, size = sizeof(dest));

playerid - The player to obtain data from.
listitem - The listitem of which data/string has to be obtained.
dest[] - Array to store string/data.
filter = false - Whether to filter the contents in a list-item. If filter is set to true,
                   it will automatically remove color embedding and make it look like
                   how it's shown to clients / players.
                   If filter is set to false (by default it'
s false), it will show the raw data
                   which may or may not include color embedding, depending on how the
                   code is.
size = sizeof(dest) - The size of destination array.
- Fixed functions : Functions from safeDialogs can now be used under OnDialogResponse and OnDialogSpoof.
- Include initialization won't call OnPlayerConnect completely anymore, instead it only resets necessary variables. This also means that "_ALS_" hook errors upon including certain libraries along with safeDialogs, are fixed.

This is an optional update, but I'd recommend anyone using this include to update to the latest version.

-----


Output of how the whole text can be retrieved for tabbed dialogs. (The same applies for header type dialogs)

pawn Code:
ShowPlayerDialog(playerid, 1, DIALOG_STYLE_TABLIST,
"DIALOG_STYLE_TABLIST",
"Item\t1\n\
{FF0000}Stuff\t2\n\
{FFFaf9}Other\t3"
, "Select", "Close");

public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[]) {

    if(dialogid == 1) {
   
        new
            tmpString[256];
           
        GetPlayerDialogItem(playerid, listitem, tmpString, false, sizeof(tmpString));
        //filter is false - This output can include color embedding if the script has done so.
        printf("%s", tmpString);
       
        tmpString[0] = EOS;
        GetPlayerDialogItem(playerid, listitem, tmpString, true, sizeof(tmpString));
        //filter is true - It will print the text exactly like how clients view in game.
        printf("%s", tmpString);
       
        return 1;
    }
    return 0;
}
Output: (I selected each and every list-items)
Code:
Item	1
Item	1
{FF0000}Stuff	2
Stuff	2
{FFFaf9}Other	3
Other	3
Reply
#17

OnDialogSpoof got called for no reason again and the spoof type was dialog ID. This is what my dialog looked like: https://gyazo.com/ed8c0f8b1d392086fd890bb8d15579f7
Responding to it showed this dialog:
https://gyazo.com/f88309606a29a632457e6f7e1966fc22
and after I responded to the second dialog OnDialogSpoof got called.
I printed the dialog IDs:
Code:
dialogid: 52
g_LSafeDialogs_Player[playerid][e_L_SD_pDIALOG_ID]: -1
I tried going through the include, but I couldn't find what's causing that. It was working before the 1.0.3 update though.
Reply
#18

Quote:
Originally Posted by GoldenLion
View Post
OnDialogSpoof got called for no reason again and the spoof type was dialog ID. This is what my dialog looked like: https://gyazo.com/ed8c0f8b1d392086fd890bb8d15579f7
Responding to it showed this dialog:
https://gyazo.com/f88309606a29a632457e6f7e1966fc22
and after I responded to the second dialog OnDialogSpoof got called.
I printed the dialog IDs:
Code:
dialogid: 52
g_LSafeDialogs_Player[playerid][e_L_SD_pDIALOG_ID]: -1
I tried going through the include, but I couldn't find what's causing that. It was working before the 1.0.3 update though.
Are you using multiple filterscripts that uses dialog features? If so, please wait because I'll have to change the data structure to use PVars. I'm currently on a tour and will be updating as soon as I get back.

If what I said is your problem, for now return 1 under your OnDialogResponse. If this isn't the problem, try compiling with v1.0.2 (can be taken from commit history) and see if it's working well or not.

Edit : One more thing I'd like to add - Are you calling OnDialogResponse callback explicitly anywhere on your code? Also let me know if you're using easyDialogs or not.
Reply
#19

Quote:
Originally Posted by Lordzy
View Post
Are you using multiple filterscripts that uses dialog features? If so, please wait because I'll have to change the data structure to use PVars. I'm currently on a tour and will be updating as soon as I get back.

If what I said is your problem, for now return 1 under your OnDialogResponse. If this isn't the problem, try compiling with v1.0.2 (can be taken from commit history) and see if it's working well or not.

Edit : One more thing I'd like to add - Are you calling OnDialogResponse callback explicitly anywhere on your code? Also let me know if you're using easyDialogs or not.
I don't have any filterscripts nor easyDialogs include and I don't call OnDialogResponse anywhere. Also I return 1 there already, I never return 0. :P I'll try 1.0.2.
Reply
#20

Quote:
Originally Posted by GoldenLion
View Post
I don't have any filterscripts nor easyDialogs include and I don't call OnDialogResponse anywhere. Also I return 1 there already, I never return 0. :P I'll try 1.0.2.
You should have OnDialogResponse defined in your script, even if there's nothing to do with it, for now.
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)