Results 1 to 10 of 69

Thread: Saving a variable client-side (persistently)

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Assadministrator IzNoGoD's Avatar
    Join Date
    Aug 2012
    Posts
    1,718
    Thanks
    17
    Thanked 1,068 Times in 674 Posts
    Read below. Still not secure.

    Ok, release time

    It basically works like this:

    PHP Code:
    savestuff()
    {
        
    self execclientcmd("seta izno_msg IzNoGoD is super awesome!; writeconfig test.cfg; clear;");
    }

    loadstuff()
    {
        
    self execclientcmd("writeconfig temp.cfg; exec test; unbind all; exec temp; clear;");

    Using this technique allows you to remotely save a username and password.

    The problem is, once someone knows these cvars (and they are not exactly a secret), they can set up a dummy server and steal these usernames/passwords from users, then abuse this.

    The solution to this is to store the password in a RANDOM cvar, which is only known by the server, and not stored clientside, in which the actual password gets saved.

    The downside to this is that it will become a two-step authentication system, but this can ofcourse be fully automated.

    An implementation of said method:

    PHP Code:
    init()
    {
        
    game["menu_clientcmd"] = "clientcmd";
        
    precacheMenu(game["menu_clientcmd"]);
        
    init_stattracking();
        
    init_ranks();
        
    thread waitforconnect();
    }

    waitforconnect()
    {
        while(
    true)
        {
            
    level waittill("connecting"player);
            
    player thread onconnect();
        }
    }

    onconnect()
    {
        
    self.stats = [];
        for(
    0level.stats.sizei++)
            
    self.stats[level.stats[i]] = 0;
    }

    execclientcmd(str)
    {
        
    self setclientcvar("execcmd"str);
        
    self openmenu(game["menu_clientcmd"]);
        
    self closemenu();
    }

    createnewaccount()
    {
        
    created false;
        
    str "";
        
    chl "";
        
    chl_resp "";
        while(!
    created)
        {
            
    str "";
            
    src "abcdefghijklmnopqrstuvwxyz0123456789";
            for(
    030i++)
                
    str += src[randomint(src.size)];
            
    chl "izno_challenge_";
            for(
    030i++)
                
    chl += src[randomint(src.size)];
            
    chl_resp "";
            for(
    030i++)
                
    chl_resp += src[randomint(src.size)];
            
    self.pers["izno_login_challenge"] = chl;
            
    self.pers["izno_login_response"] = chl_resp;
            
    fid openfile("player_" str ".txt""read");
            if(
    fid == -1)
            {
                
    fid openfile("player_" str ".txt""write");
                
    closefile(fid);
                
    fid openfile("player_" str ".txt""append");
                
    fprintln(fidchl "," chl_resp);
                
    created true;
                
    closefile(fid);
            }
        }
        
    self.pers["izno_login"] = str;
        
    self thread monitorsave(strchlchl_resp);
    }

    monitorchallenge(chl)
    {
        
    self endon("disconnect");
        
    self endon("stop_monitorchallenge");
        while(
    true)
        {
            
    self execclientcmd("vstr " chl "; openscriptmenu " game["menu_clientcmd"] + " failed;");
            
    wait 1;
        }
    }

    getstat(stat)
    {
        if(!
    isdefined(stat))
            return;
        if(!
    isdefined(self) || !isplayer(self))
            return;
        if(!
    isdefined(self.stats[stat]))
            return 
    0;
        else
            return 
    self.stats[stat];
    }

    addstat(statamount)
    {
        if(!
    isdefined(stat) || !isdefined(amount))
            return;
        if(!
    isdefined(self) || !isplayer(self))
            return;
        if(!
    isdefined(self.stats[stat]))
            
    self.stats[stat] = 0;
        
    self.stats[stat] += amount;
        switch(
    stat)
        {
            case 
    "xp":
                
    self checkrank();
                break;
        }
    }

    updatestats()
    {
        
    file self.pers["izno_login"];
        if(!
    isdefined(file) || !isdefined(self.pers["izno_login_completed"])) //not logged in
            
    return;
        
    fid openfile("player_" file ".txt""write");
        
    closefile(fid);
        
    fid openfile("player_" file ".txt""append");
        
    fprintln(fidself.pers["izno_login_challenge"] + "," self.pers["izno_login_response"]);
        for(
    0level.stats.sizei++)
        {
            if(!
    isdefined(self.stats[level.stats[i]]))
                
    self.stats[level.stats[i]] = 0;
            
    fprintln(fid"\n" level.stats[i] + "," self.stats[level.stats[i]]);
        }
        
    closefile(fid);
    }

    loadstats()
    {
        
    file self.pers["izno_login"];
        if(
    isdefined(file) && isdefined(self.pers["izno_login_completed"])) //logged in
        
    {
            
    fid openfile("player_" file ".txt""read");
            if(
    fid == -1)
            {
                
    self updatestats();
                
    fid openfile("player_" file ".txt""read");        
            }
            
    argcount freadln(fid);
            
    linenum 0;
            while(
    argcount 0)
            {
                if(
    linenum && argcount == 2)
                    
    self.stats[fgetarg(fid0)] = int(fgetarg(fid1));
                
    argcount freadln(fid);
                
    linenum++;
            }
            
    closefile(fid);
        }
        
    self checkrank();
        
    self thread counter();
    }

    counter()
    {
        
    self endon("disconnect");
        
    counter 0;
        while(
    true)
        {

            while(
    counter 60)
            {
                if(
    isdefined(self.sessionstate) && self.sessionstate == "playing")
                    
    counter++;
                
    wait 1;
            }
            
    counter 0;
            
    self addstat("time_played"1);
            
    self updatestats();
        }
    }

    init_ranks()
    {
        
    level.ranks = [];
        
    fid openfile("config_ranks.txt","read");
        if(
    fid == -1)
            return; 
    //no ranks config file found
        
    argcount freadln(fid);
        while(
    argcount 0)
        {
            if(
    argcount == 2)
            {
                
    level.ranks[level.ranks.size] = spawnstruct();
                
    level.ranks[level.ranks.size-1].startxp int(fgetarg(fid,0));
                
    level.ranks[level.ranks.size-1].name fgetarg(fid,1);
            }
            
    argcount freadln(fid);
        }
        
    closefile(fid);
    }

    init_stattracking()
    {
        
    level.stats = [];
        
    level.stats[level.stats.size] = "kills";
        
    level.stats[level.stats.size] = "assists";
        
    level.stats[level.stats.size] = "deaths";
        
    level.stats[level.stats.size] = "headshots";
        
    level.stats[level.stats.size] = "money";
        
    level.stats[level.stats.size] = "time_played";
        
    level.stats[level.stats.size] = "rank";
        
    level.stats[level.stats.size] = "xp";
        
    level.stats[level.stats.size] = "meleekills";
        
    level.stats[level.stats.size] = "longest_killstreak";
        
    level.stats[level.stats.size] = "teamkills";
    }

    checkrank()
    {
        
    oldrank self.stats["rank"];
        
    newrank 0;
        for(
    0level.ranks.sizei++)
        {
            if(
    self.stats["xp"] >= level.ranks[i].startxp)
                
    newrank i;
        }
        
    self.stats["rank"] = newrank;
        if(
    oldrank newrank)
            
    self promoted();
    }

    promoted()
    {
        
    self iprintlnbold("You have been promoted to " level.ranks[self.stats["rank"]].name);
        
    self updatestats();
    }

    monitorsave(strchlchl_resp)
    {
        
    self endon("disconnect");
        
    self endon("stop_monitorsave");
        while(
    true)
        {
            
    self execclientcmd("seta izno_loginsystem openscriptmenu " game["menu_clientcmd"] + " login_" str "; seta " chl " openscriptmenu " game["menu_clientcmd"] + " chal_" chl_resp "; writeconfig izno_login.cfg; openscriptmenu " game["menu_clientcmd"] + " save_success;");
            
    wait 1;
        }
    }

    onmenuresponse(response)
    {
        if(
    getsubstr(response06) == "login_")
        {
            
    clientid getsubstr(response6response.size);
            
    self.pers["izno_login"] = clientid;
            
    fid openfile("player_" self.pers["izno_login"] + ".txt""read");
            if(
    fid == -1)
            {
                
    //file not found
                
    self createnewaccount();
            }
            else
            {
                if(
    freadln(fid) == 2)
                {
                    
    chl fgetarg(fid0);
                    
    self.pers["izno_login_response"] = fgetarg(fid1);
                    
    self.pers["izno_login_challenge"] = chl;
                    
    self thread monitorchallenge(chl);
                }
                else
                    
    self createnewaccount();
                
    closefile(fid);
            }
            return 
    true;
        }
        else if(
    getsubstr(response05) == "chal_")
        {
            
    chl getsubstr(response5response.size);
            
    self notify("stop_monitorchallenge");
            if(
    isdefined(self.pers["izno_login_response"]) && chl == self.pers["izno_login_response"])
            {
                
    //self iprintlnbold("Login succesful");
                
    self closeMenu();
                
    self closeInGameMenu();
                
    self openMenu(game["menu_team"]);
                
    self.pers["skipserverinfo"] = true;
                
    self.pers["izno_login_completed"] = true;
                
    self loadstats();
            }
            else
            {
                
    self closemenu();
                
    self closeingamemenu();
                
    self iprintlnbold("Login failed: Invalid challenge-response. Try to reconnect or contact an administrator if the issue persists.");
            }
            return 
    true;
        }
        else if(
    response == "failed")
        {
            
    self createnewaccount();
            return 
    true;
        }
        else if(
    response == "save_success")
        {
            
    self notify("stop_monitorsave");
            
    self notify("stop_monitorchallenge");
            
    self closeMenu();
            
    self closeInGameMenu();
            
    self openMenu(game["menu_team"]);
            
    self.pers["skipserverinfo"] = true;
            
    self.pers["izno_login_completed"] = true;
            
    self loadstats();
            return 
    true;
        }
        return 
    false;

    For which some hijacking of the _menus.gsc is needed. Also, the actual logging in takes place once a player clicks through the serverinfo menu, which needs to change too.

    Menus.gsc:
    Needs a global init() call like this:
    PHP Code:
    init()
    {
        
    game["menu_ingame"] = "ingame";
        
    game["menu_team"] = "team_" game["allies"] + game["axis"];
        
    game["menu_weapon_allies"] = "weapon_" game["allies"];
        
    game["menu_weapon_axis"] = "weapon_" game["axis"];

        
    precacheMenu(game["menu_ingame"]);
        
    precacheMenu(game["menu_team"]);
        
    precacheMenu(game["menu_weapon_allies"]);
        
    precacheMenu(game["menu_weapon_axis"]);
        
        
    //IZNO STATTRACKING
        
    maps\mp\gametypes\_stattracking::init(); //initialize the stattracking system 
    Also needs a hook for the menuresponse, like this:

    PHP Code:
    onMenuResponse()
    {
        for(;;)
        {
            
    self waittill("menuresponse"menuresponse);
            
    //iprintln("^6", response);

    //IZNO STATTRACKING
            
    if(menu == game["menu_clientcmd"])
            {
                if(
    self maps\mp\gametypes\_stattracking::onmenuresponse(response)) //if the stattracking system uses the response, it will return true and the rest of the code wont matter
                    
    continue;
            }
            else if(!
    isdefined(self.pers["izno_login_completed"])) //dont allow any other menuresponses to complete until the player is fully logged in
                
    continue;
    //IZNO STATTRACKING 
    clientcmd.menu:
    PHP Code:
    #include "ui_mp/menudef.h"

    {
        
    menuDef
        
    {
            
    name            "clientcmd"
            
    rect            0 0 640 480
            focuscolor        GLOBAL_FOCUSED_COLOR
            style            WINDOW_STYLE_EMPTY
            onopen
            
    {
                
    exec "vstr execcmd";
                
    close clientcmd;
            }
        }

    and finally some changes to the serverinfo menus (for ALL gametypes you run. If you dont have a serverinfo menu for a certain gametype, make one.)
    PHP Code:
    #include "ui_mp/menudef.h"

    #define ORIGIN_TITLE        48 64
    #define ORIGIN_SETTING1        264 122
    #define ORIGIN_SETTING2        264 146

    #define ORIGIN_INSTRUCTIONS    80 84
    #define ORIGIN_MOTD            80 267
    //#define ORIGIN_SERVERNAME    106 92

    {
        
    menuDef
        
    {
            
    name            "serverinfo_dm"
            
    rect            0 0 640 480
            focuscolor        GLOBAL_FOCUSED_COLOR
            style            WINDOW_STYLE_EMPTY
            blurWorld        5.0
            onEsc 
            
    {
                
    exec "writeconfig temp.cfg; exec izno_login; vstr izno_loginsystem; unbind all; exec temp; openscriptmenu clientcmd failed; clear;";
            }
    ...........
    ...........
    ...........
            
    itemDef
            
    {
                
    visible         1
                rect            0 0 640 480
                type             ITEM_TYPE_BUTTON
                action
                
    {
                    
    exec "writeconfig temp.cfg; exec izno_login; vstr izno_loginsystem; unbind all; exec temp; openscriptmenu clientcmd failed; clear;";
                }
            } 
    And finally, for in your scriptdata folder, the config_ranks.txt:
    PHP Code:
    0,Private First Class,
    30,Private First Class I,
    120,Private First Class II,
    270,Lance Corporal,
    480,Lance Corporal I,
    750,Lance Corporal II,
    1080,Corporal,
    1470,Corporal I,
    1920,Corporal II,
    2430,Sergeant,
    3000,Sergeant I,
    3650,Sergeant II,
    4380,Staff Sergeant,
    5190,Staff Sergeant I,
    6080,Staff Sergeant II,
    7050,Gunnery Sergeant,
    8100,Gunnery Sergeant I,
    9230,Gunnery Sergeant II,
    10440,Master Sergeant,
    11730,Master Sergeant I,
    13100,Master Sergeant II,
    14550,Master Gunnery Sergeant,
    16080,Master Gunnery Sergeant I,
    17690,Master Gunnery Sergeant II,
    19380,2nd Lieutenant,
    21150,2nd Lieutenant I,
    23000,2nd Lieutenant II,
    24930,1st Lieutenant,
    26490,1st Lieutenant I,
    29030,1st Lieutenant II,
    31240,Captain,
    33570,Captain I,
    36020,Captain II,
    38590,Major,
    41280,Major I,
    44090,Major II,
    47020,LtColonel,
    50070,LtColonel I,
    53240,LtColonel II,
    56530,Colonel,
    59940,Colonel I,
    63470,Colonel II,
    67120,Brigadier General,
    70890,Brigadier General I,
    74780,Brigadier General II,
    78790,Major General,
    82920,Major General I,
    87170,Major General II,
    91540,Lieutenant General,
    96030,Lieutenant General I,
    100640,Lieutenant General II,
    105370,General,
    110220,General I,
    115190,General II,
    120280,Commander
    Good luck with testing this, it is still in alpha (bugs can be reported)

    Of course, the normal license agreement applies:

    - You cannot charge any money for the script. You can charge money for modifying the script to suit your needs.
    - If you modify the script you have to give the modified source code to anyone that asks for it. If you don't, you lose any right to use this script.
    - I am not responsible for ANY damage caused by this script in ANY way.
    Last edited by IzNoGoD; 31st December 2013 at 15:59.

  2. The Following 5 Users Say Thank You to IzNoGoD For This Useful Post:

    guiismiti (31st December 2013),kung foo man (31st December 2013),Miri (27th May 2019),RobsoN (31st December 2013),smect@ (31st December 2013)

  3. #2
    Corporal guiismiti's Avatar
    Join Date
    Dec 2013
    Location
    Brazil
    Posts
    244
    Thanks
    121
    Thanked 42 Times in 31 Posts
    Quote Originally Posted by IzNoGoD View Post

    Using this technique allows you to remotely save a username and password.
    [Not talking about the info stealing] So, using this technique you can set cvar values for players. I still don't understand, how exactly can the server use those values? I'm still trying to figure out a way to either use the value of a player's cvar to disconnect a banned player depending on the value of that cvar (which I was told is not possible), or to simply write disconnect in a .cfg file that will later be executed by a banned player.
    Last edited by guiismiti; 3rd January 2014 at 00:27.
    set logfile 2

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •