Monday 20 March 2017

Web Tutorial: Hacker Republic Login Sequence (Part 4/4)

This is the final part, and it may come off as a bit dry. Bear with me - we'll be recycling some functions we previously wrote.

Salander knew it was no empty threat. If she wrote the wrong password three times in a row the site would shut down and the name Wasp would be struck from the membership list. Carefully she wrote the password MonkeyBusiness.

The screen changed again and now had a blue background with the text:

[Welcome to Hacker Republic, citizen Wasp. It has been 56 days since your last visit. There are 11 citizens online. Do you want to (a) Browse the Forum (b) Send a Message (c) Search the Archive (d) Talk (e) Get Laid?]


Here, we're going to implement some click events on the buttons. They will call the login() function again, but with different parameters.

confirm.php
        <div id="speech_wrapper">
            <div id="speech">
                <div id="confirmid">
                    <br />
                    WHO GOES THERE?
                    <br />
                    <input type="text" id="txtConfirmId" maxlength="20">
                    &nbsp;
                    <input type="button" value="go" onclick="login('confirm_form_login');">
                </div>
                <div id="confirmpassword">
                    <br />
                    PROVE IT, OR ELSE....
                    <br />
                    <input type="password" id="txtConfirmPassword" maxlength="20">
                    &nbsp;
                    <input type="button" value="go" onclick="login('confirm_form_password');">
                </div>
            </div>
        </div>


Back to your JavaScript, let's modify the login() function by putting in If blocks for the different cases we've just specified.

tt_millenniumlogin.js
function login(formid)
{
    var parameters;

    if (formid=="login_form")
    {
        document.getElementById("login_form").style.display="none";
        document.getElementById("login_message").style.display="block";

        parameters="type=0";
        parameters=parameters+"&id="+document.getElementById("login_id").value;
        parameters=parameters+"&password="+document.getElementById("login_password").value;

        if (window.XMLHttpRequest)
        {// code for IE7+, Firefox, Chrome, Opera, Safari
            xmlhttp_loginform=new XMLHttpRequest();
        }
        else
        {// code for IE6, IE5
            xmlhttp_loginform=new ActiveXObject("Microsoft.XMLHTTP");
        }
       
        xmlhttp_loginform.onreadystatechange=function()
        {
            if (xmlhttp_loginform.readyState==4 && xmlhttp_loginform.status==200)
            {
                var logindetails=JSON.parse(xmlhttp_loginform.responseText);

                if (logindetails.valid)
                {
                    var errormessage=document.getElementsByClassName("message_error");
                    errormessage[3].onclick=function(){window.location="confirm.php"};
                }
            }
        }

        xmlhttp_loginform.open("POST","ajax_login.php",true);
        xmlhttp_loginform.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        xmlhttp_loginform.send(encodeURI(parameters));   
    }

    if (formid=="confirm_form_login")
    {

    }

    if (formid=="confirm_form_password")
    {

    }
}


So if the argument passed in is "confirm_form_login", we use a basic AJAX block. parameters is set to a string where the value of type is 1. The value of id is the string you type into the txtConfirmId textbox. The data is again sent to ajax_login.php, which will then check to see if your id is valid.
tt_millenniumlogin.js
    if (formid=="confirm_form_login")
    {
        parameters="type=1";
        parameters=parameters+"&id="+document.getElementById("txtConfirmId").value;

        if (window.XMLHttpRequest)
        {// code for IE7+, Firefox, Chrome, Opera, Safari
            xmlhttp_loginform=new XMLHttpRequest();
        }
        else
        {// code for IE6, IE5
            xmlhttp_loginform=new ActiveXObject("Microsoft.XMLHTTP");
        }
       
        xmlhttp_loginform.onreadystatechange=function()
        {
            if (xmlhttp_loginform.readyState==4 && xmlhttp_loginform.status==200)
            {

            }
        }

        xmlhttp_loginform.open("POST","ajax_login.php",true);
        xmlhttp_loginform.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        xmlhttp_loginform.send(encodeURI(parameters));   
    }

    if (formid=="confirm_form_password")
    {

    }


Remember this code? Now add to it an IF block for the case of the value of type being 1.

ajax_login.php
<?php
session_start();

$type=intval($_POST["type"]);

if ($type==0)
{
    $logins=array();
    $logins["Remarkable"]="A(89)Cx#magnolia";
    $logins["x1"]="x1";
    $logins["x2"]="x2";

    $id=$_POST["id"];
    $password=$_POST["password"];

    if (array_key_exists($id,$logins))
    {
        if ($logins[$id]==$password)
        {
            $_SESSION["loggedin"]=true;
            echo json_encode(array("valid" => true));
        }
        else
        {
            echo json_encode(array("valid" => false));
        }
    }
    else
    {
        echo json_encode(array("valid" => false));
    }
}

if ($type==1)
{

}
?>


Again, we'll enter in some test data in the logins array. In Lisbeth's case, her id is "Wasp" and her password is "MonkeyBusiness", so we definitely should make it one of the datasets. We'll also add in "x3" and "x4" as test data, with passwords identical to the ids. After that, whatever you do is similar to what you already did in the first If block. Check if id exists as a key in the logins array. If so, set the session variable login to id and return a true JSON string. If not, print out a false JSON string.

ajax_login.php
<?php
if ($type==1)
{
    $logins=array();
    $logins["Wasp"]="MonkeyBusiness";
    $logins["x3"]="x3";
    $logins["x4"]="x4";

    $id=$_POST["id"];

    if (array_key_exists($id,$logins))
    {
        $_SESSION["login"]=$id;
        echo json_encode(array("valid" => true));
    }
    else
    {
        echo json_encode(array("valid" => false));
    }
}
?>


Again, back to your JavaScript, handle the output accordingly. If the login id is valid, use the confirm_screen() function to switch the content in the speech bubble and change the picture in the "doorway". If not, do the exact opposite.

tt_millenniumlogin.js
    if (formid=="confirm_form_login")
    {
        parameters="type=1";
        parameters=parameters+"&id="+document.getElementById("txtConfirmId").value;

        if (window.XMLHttpRequest)
        {// code for IE7+, Firefox, Chrome, Opera, Safari
            xmlhttp_loginform=new XMLHttpRequest();
        }
        else
        {// code for IE6, IE5
            xmlhttp_loginform=new ActiveXObject("Microsoft.XMLHTTP");
        }
       
        xmlhttp_loginform.onreadystatechange=function()
        {
            if (xmlhttp_loginform.readyState==4 && xmlhttp_loginform.status==200)
            {
                var logindetails=JSON.parse(xmlhttp_loginform.responseText);

                if (logindetails.valid)
                {
                    confirm_screen(false,true);
                }
                else
                {
                    confirm_screen(true,false);
                }
            }
        }

        xmlhttp_loginform.open("POST","ajax_login.php",true);
        xmlhttp_loginform.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        xmlhttp_loginform.send(encodeURI(parameters));   
    }

    if (formid=="confirm_form_password")
    {

    }


Try it! Try entering "Wasp", "x3" or "x4". You should see the text in the speech bubble change to this, and the Lara Croft-like figure cock her gun. With any other input, nothing changes.


And of course, we will now handle the last case in the login() function in your JavaScript, via another AJAX block. This time, the value of type is 2, and we send the password over.

tt_millenniumlogin.js
    if (formid=="confirm_form_password")
    {
        parameters="type=2";
        parameters=parameters+"&password="+document.getElementById("txtConfirmPassword").value;

        if (window.XMLHttpRequest)
        {// code for IE7+, Firefox, Chrome, Opera, Safari
            xmlhttp_loginform=new XMLHttpRequest();
        }
        else
        {// code for IE6, IE5
            xmlhttp_loginform=new ActiveXObject("Microsoft.XMLHTTP");
        }
       
        xmlhttp_loginform.onreadystatechange=function()
        {
            if (xmlhttp_loginform.readyState==4 && xmlhttp_loginform.status==200)
            {

            }
        }

        xmlhttp_loginform.open("POST","ajax_login.php",true);
        xmlhttp_loginform.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        xmlhttp_loginform.send(encodeURI(parameters));
    }


In your PHP code, we'll, of course, start off by providing another If block for the case where the value of type is 2.

ajax_login.php
<?php
if ($type==1)
{
    $logins=array();
    $logins["Wasp"]="MonkeyBusiness";
    $logins["x3"]="x3";
    $logins["x4"]="x4";

    $id=$_POST["id"];

    if (array_key_exists($id,$logins))
    {
        $_SESSION["login"]=$id;
        echo json_encode(array("valid" => true));
    }
    else
    {
        echo json_encode(array("valid" => false));
    }
}

if ($type==2)
{

}
?>


The test data is identical to the last If block's. We grab the password and check if the value of the element denoted by the key, which is the current session variable login, is the same. If the values match, the login is successful. The session variable confirmed is set to true, and a true JSON string is printed. If not, the session variable attempts is incremented (if it didn't previously exist, the default value is 0. Not particularly elegant, but it works). Then both a false value and the number of attempts is output in a JSON string.

ajax_login.php
<?php
if ($type==2)
{
    $logins=array();
    $logins["Wasp"]="MonkeyBusiness";
    $logins["x3"]="x3";
    $logins["x4"]="x4";

    $password=$_POST["password"];

    if ($logins[$_SESSION["login"]]==$password)
    {
        $_SESSION["confirmed"]=true;
        echo json_encode(array("valid" => true));
    }
    else
    {
        $_SESSION["attempts"]=$_SESSION["attempts"]+1;
        echo json_encode(array("valid" => false, "attempts" => $_SESSION["attempts"]));
    }
}
?>


So back to your JavaScript, we handle a successful login by sending the user to dashboard.php. If the login is unsuccessful (ie, the password is incorrect), use the confirm_screen() function to ask for the id again. Then check the number of attempts in the decoded JSON string. If the number is greater than 3, output a self-destruct message and redirect back to index.html.

tt_millenniumlogin.js
    if (formid=="confirm_form_password")
    {
        parameters="type=2";
        parameters=parameters+"&password="+document.getElementById("txtConfirmPassword").value;

        if (window.XMLHttpRequest)
        {// code for IE7+, Firefox, Chrome, Opera, Safari
            xmlhttp_loginform=new XMLHttpRequest();
        }
        else
        {// code for IE6, IE5
            xmlhttp_loginform=new ActiveXObject("Microsoft.XMLHTTP");
        }
       
        xmlhttp_loginform.onreadystatechange=function()
        {
            if (xmlhttp_loginform.readyState==4 && xmlhttp_loginform.status==200)
            {
                var logindetails=JSON.parse(xmlhttp_loginform.responseText);

                if (logindetails.valid)
                {
                    window.location="dashboard.php";
                }
                else
                {
                    confirm_screen(true,false);

                    if (parseInt(logindetails.attempts)>3)
                    {
                        alert("ACTIVATING DESTRUCT SEQUENCE...");
                        window.location="index.html";
                    }
                }
            }
        }

        xmlhttp_loginform.open("POST","ajax_login.php",true);
        xmlhttp_loginform.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        xmlhttp_loginform.send(encodeURI(parameters));
    }
    }


We'll need dashboard.php. So create it, and use this code. A session is created, and then the server checks if the session variable confirmed is true. This prevents unauthorized access, because you could only have confirmed set to true if you logged in.

dashboard.php
<?php
session_start();

if ($_SESSION["confirmed"])
{
?>

<?php
}
?>


Then add in the HTML and CSS. This is pretty bare. I could add more text to this, but I think you get the idea by now.
<?php
session_start();

if ($_SESSION["confirmed"])
{
?>

<!DOCTYPE html>
<html>
    <head>
        <title>Hacker Republic</title>

        <style>
            body
            {
                background-color:#0000FF;
                color:#FFFFFF;
                font-family: monospace;
            }
        </style>
    </head>
    <body>
        <h1>Welcome to the Hacker Republic, citizen <?php echo $_SESSION["login"];?>.</h1>
    </body>
</html>

<?php
}


Try attempting to log in unsuccessfully more than 3 times.


Now try logging in with a proper id and password...


Conclusion

What a neat login sequence. Certain things could have been done more securely, but I just wanted to simulate the front-end. The look and feel wasn't all that important, though as a matter of pride, I've tried to establish a bare minimum of prettiness.

Welcome to the Hacker Republic!
T___T

No comments:

Post a Comment