04.05.2009, 23:14
[Tutorial] Register/Login System Using DJson, DCMD, and Whirlpool password encryption! *Includes DUDB Conversion!
Difficulty: Pretty Easy - Some basic scripting knowledge is helpful.
NOTE: You are only hurting yourself by just copy and pasting these scripts, you will be confused and not know what do to. I will NOT provide ANY support on this if you haven't first read the topic. It really, really, doesn't get much simpler than this. I've explained everything out for you. Read this tutorial so you can actually learn some things. You won't get anywhere by copy and pasting and than telling all your buddies that you made it, even though you didn't do anything.
A few notes before beggining:
A string is a linear sequence of symbols (characters or words or phrases) Basically just text.
An Int(Integer) is any of the natural numbers (positive or negative) or zero, an integer is a number that is not a fraction.
I know I've probably made some speling errors and mistakes, please point them out to me so I can fix them. Nobody's perfect :P
I've always used DUDB for my user-files and such and when DJson came out I couldn't really understand it and I though since I've always used DUDB, it would take AGES of time to convert all the code. One day I saw a Account System include called Cez-Account. I downloaded it but still had the problem with the DUDB stuff. A few days ago I went back to look at it and added a simple fix to convert every DUDB line to work with the include/DJson. I made some little changes to the include and started making a register & login script.
So today I will make a tutorial on how to create a Register/Login script using DJson, and that include.
You can find the original cez-account include topic here: http://forum.sa-mp.com/index.php?topic=84762.0
But I suggest you use mine since that is what I will be using in this tutorial.
1. First open up pawno to a blank screen. Copy the code below, paste it into your blank pawno script. Click File -> Save as and locate to your \pawno\includes folder. Save it with the name, 'ACC.inc'. You do not need to press compile, all you need to do is save it to your includes folder. Also, the tabs have been replaced with the correct amount of spaces, meaning you should be able to read and copy/paste it perfectly.
2. Second, we need to get the Whirlpool plugin by Y-Less. Get the appropriate version here:
http://forum.sa-mp.com/index.php?topic=89418.0
If you do not wish to use Whirlpool than comment out: native WP_Hash(buffer[], len, const str[]); in the include!
For this tutorial I am using Whirlpool for password encryption, if you want to use something else than you need to figure out how to use it. Do NOT post here asking me how to implement a different password encryption system please.
Once you have downloaded the Whirlpool plugin, put it into your \plugins\ folder. (If you do not have a plugins folder create it with that exact name, 'plugins'.)
Now, go to your server.cfg and add this: plugins Whirlpool.dll on a separate line. (.dll is for windows, i'm not familiar with how to do it on Linux, sorry ) If you have other plugins just add Whirlpool.dll on to that list, example: plugins YourPlugin1.dll YourPlugin2.dll Whirlpool.dll
3. Okay now it's time to get into the actualy scripting of the command using our new include and Whirlpool plugin.
Alright, lets deal with /register first. Here's some information. The way we will be doing this is we have one file called accounts.json Inside there we have a category for each person's name aka each name that is registered with your server. Inside each person's 'category' we have all of there information saved. DJson will put all of the information in alphabetical order also.
P.S: This diagram took me like 45 minutes to get right, so you better enjoy it!
Okay, now lets get onto the pawn scripting part. For this tutorial I will be using DCMD.
If you are unfamiliar with DCMD, there is a tutorial about it here: http://forum.sa-mp.com/index.php?topic=75000.0
First we must change our includes and add 2 defines. If you use DUDB, comment or delete the: #include <DUDB>
At the top of your script add:
#include <ACC>
#define COLOR_SUCCESS 0x64F600FF
#define COLOR_RED 0xFF0000FF
You can change those colors to whatever you want, just have them defined, or change it in the script.
Now we start with the register command. We add it into OnPlayerCommandText:
Now we make our basic command function here.
The first thing we will do is check if their account already exists. To do this we will get the name of the player and use AccountExists();
If you are confused on what we did here read on.
First, we create a spot to put the players current username. We then get the name and store it in that spot. We ask the server if the account doesn't exist, than continue. Otherwise it will go down to the end of the } and to the else's. Some people get confused with the else's. Basically all we are doing is if it finds the account does exist, it will skip down there for further instruction. The first one says if they are not logged on, (the vlaue "LoggedOn" we will set later) send them a message saying their account already exists and to use /login password to login to their account. Than the second else is called if the first one isn't true. Basically it means if they are logged on. In order to be logged on they must have an account already so it just tells them that they are already logged on.
Now let's move onto the core:
First we will check a few things on their password..
Okay now as you can see we've added 3 if's. First of all, strlen stands for, "string length". Params is the information submitted by the user after, '/register ' which means if I were to type in /register ThisIsMyPass, params would be, "ThisIsMyPass". So here we check if they submit any information. If they didn't submit any information as in they just typed /register without anything else, it tells them the syntax of the command and that the password is Case Sensitive. Case Sensitive means capital letters make a difference. Meaning, If I do /register Hello and try to do /login hello it would say my password was wrong because I used a lowercase h. The second if checks if the length of params is over 20. If it is we tell them their password cannot be over 20 characters long. The third checks if the length of params is less than 3. If it is we tell them their password cannot be less than 3 characters long.
Alright, so now we are ready to create their account with their password and set some data.
Alright, now we have some pretty lengthy code :P
Let's take a look and see what we are doing here.
First, we create a spot to store something for DJson. For this i'm using the actual DJson functions, not the include functions. str is just short for string here. Now we format some text into here. What you see here is %s/password %s stands for string, which means we are putting a string into there. In this case it's the name of the player. As seen in the diagram above, we submit the PlayerName(username) as the first category, than the key is password which we set in a moment. So now we have the location ready. Now we will take the password they submitted into the command and encrypt it into a cryptographic code. In layman's terms: a secret code that nobody can read. We create a buf with the length of 145. 145 is the minimum amount that Whirlpool. Whenever using the Whirlpool for passwords in your script you should keep it consistent. I suggest just using 145. Buf is just what we are storing the secret code to. WP_Hash is a function included with ******'s Whirlpool plugin, used to encrypt text. In this case our text is the information they submitted which we now know is stored in params.
Now we will set the password in their account, BUT WAIT! We never did any Create account thingy!! Don't worry, DJson will automatically create it. So now we have set the password to their account. Now we set two more things, the LoggedIn value, which we set to 0, and I set the password again to make sure it was set. And we send a message to them saying they have successfully been registered and that you can now use /login to login.
Alright, were done with the registration command, bathroom break!
Continued below because I couldn't fit everything within the 20000 character limit
Difficulty: Pretty Easy - Some basic scripting knowledge is helpful.
NOTE: You are only hurting yourself by just copy and pasting these scripts, you will be confused and not know what do to. I will NOT provide ANY support on this if you haven't first read the topic. It really, really, doesn't get much simpler than this. I've explained everything out for you. Read this tutorial so you can actually learn some things. You won't get anywhere by copy and pasting and than telling all your buddies that you made it, even though you didn't do anything.
A few notes before beggining:
A string is a linear sequence of symbols (characters or words or phrases) Basically just text.
An Int(Integer) is any of the natural numbers (positive or negative) or zero, an integer is a number that is not a fraction.
I know I've probably made some speling errors and mistakes, please point them out to me so I can fix them. Nobody's perfect :P
I've always used DUDB for my user-files and such and when DJson came out I couldn't really understand it and I though since I've always used DUDB, it would take AGES of time to convert all the code. One day I saw a Account System include called Cez-Account. I downloaded it but still had the problem with the DUDB stuff. A few days ago I went back to look at it and added a simple fix to convert every DUDB line to work with the include/DJson. I made some little changes to the include and started making a register & login script.
So today I will make a tutorial on how to create a Register/Login script using DJson, and that include.
You can find the original cez-account include topic here: http://forum.sa-mp.com/index.php?topic=84762.0
But I suggest you use mine since that is what I will be using in this tutorial.
1. First open up pawno to a blank screen. Copy the code below, paste it into your blank pawno script. Click File -> Save as and locate to your \pawno\includes folder. Save it with the name, 'ACC.inc'. You do not need to press compile, all you need to do is save it to your includes folder. Also, the tabs have been replaced with the correct amount of spaces, meaning you should be able to read and copy/paste it perfectly.
pawn Код:
/*
# Cez-Account v1.0
# © Copyright 2008 - 2009 Cezar Mihail Ignat
#
# Requires: DracoBlue's DJson - © Copyright 2008 DracoBlue
# http://cgarage.blogspot.com/
#
*/
// Small modifications by Lavamike
#if defined _cezacc_included
#endinput
#endif
#define _cezacc_included
#include <djson>
// DUDB Conversions
#define dUser(%1).( AccountGet(%1,
#define dUserINT(%1).( AccountGetInt(%1,
#define dUserSet(%1).( AccountSet(%1,
#define dUserSetINT(%1).( AccountSetInt(%1,
#define dUserSetFLOAT(%1).( AccountSetFloat(%1,
#define dUserFLOAT(%1).( AccountGetFloat(%1,
#define dUserIsSet(%1).( AccountIsSet(%1,
#define udb_Exists(%1) AccountExists(%1)
// Whirlpool for SA:MP by Y-Less
// http://forum.sa-mp.com/index.php?topic=89418.0
native WP_Hash(buffer[], len, const str[]);
stock num_hash(buf[]) {
new length=strlen(buf);
new s1 = 1;
new s2 = 0;
new n;
for (n=0; n<length; n++) {
s1 = (s1 + buf[n]) % 65521;
s2 = (s2 + s1) % 65521;
}
return (s2 << 16) + s1;
}
stock AccountExists(nickname[]) {
return djIsSet("accounts.json",nickname,false);
}
stock AccountRemove(nickname[]) {
return djUnset("accounts.json",nickname);
}
stock AccountSetInt(nickname[],key[],value) {
if(!AccountExists(nickname)) return false;
new str[255];
format(str, sizeof(str), "%s/%s", nickname, key);
return djSetInt("accounts.json", str, value);
}
stock AccountSetFloat(nickname[],key[],Float:value) {
if(!AccountExists(nickname)) return false;
new str[255];
format(str, sizeof(str), "%s/%s", nickname, key);
return djSetFloat("accounts.json", str, value);
}
stock AccountSet(nickname[],key[],value[]) {
if(!AccountExists(nickname)) return false;
new str[255];
format(str, sizeof(str), "%s/%s", nickname, key);
return djSet("accounts.json", str, value);
}
stock AccountGet(nickname[],key[]) {
new str[255];
format(str, sizeof(str), "%s/%s", nickname, key);
return dj("accounts.json", str);
}
stock Float:AccountGetFloat(nickname[],key[]) {
new str[255];
format(str, sizeof(str), "%s/%s", nickname, key);
return djFloat("accounts.json",str);
}
stock AccountGetInt(nickname[],key[]) {
new str[255];
format(str, sizeof(str), "%s/%s", nickname, key);
return djInt("accounts.json",str);
}
stock AccountCheckLogin(nickname[],pwd[]) {
new str[255];
format(str, sizeof(str), "%s/password", nickname);
if (djInt("accounts.json",str) == num_hash(pwd)) return true;
return false;
}
stock AccountCreate(nickname[],pwd[]) {
if (AccountExists(nickname)) return false;
new str[31];
format(str, sizeof(str), "%s/password", nickname);
new buf[145];
WP_Hash(buf, sizeof(buf), pwd);
djSet("accounts.json",str,buf);
printf("Account Created: %s - %s\n%s", nickname, pwd, buf);
return true;
}
// I'm pretty sure I added this into the DUDB include a while ago.
// I just added and converted it here since I used it in my script :P
// It just checks if a key has something set to it or not.
stock AccountIsSet(nickname[],key[]) {
new str[255];
format(str, sizeof(str), "%s/%s", nickname, key);
return djIsSet("accounts.json",str);
}
2. Second, we need to get the Whirlpool plugin by Y-Less. Get the appropriate version here:
http://forum.sa-mp.com/index.php?topic=89418.0
If you do not wish to use Whirlpool than comment out: native WP_Hash(buffer[], len, const str[]); in the include!
For this tutorial I am using Whirlpool for password encryption, if you want to use something else than you need to figure out how to use it. Do NOT post here asking me how to implement a different password encryption system please.
Once you have downloaded the Whirlpool plugin, put it into your \plugins\ folder. (If you do not have a plugins folder create it with that exact name, 'plugins'.)
Now, go to your server.cfg and add this: plugins Whirlpool.dll on a separate line. (.dll is for windows, i'm not familiar with how to do it on Linux, sorry ) If you have other plugins just add Whirlpool.dll on to that list, example: plugins YourPlugin1.dll YourPlugin2.dll Whirlpool.dll
3. Okay now it's time to get into the actualy scripting of the command using our new include and Whirlpool plugin.
Scripting
Alright, lets deal with /register first. Here's some information. The way we will be doing this is we have one file called accounts.json Inside there we have a category for each person's name aka each name that is registered with your server. Inside each person's 'category' we have all of there information saved. DJson will put all of the information in alphabetical order also.
P.S: This diagram took me like 45 minutes to get right, so you better enjoy it!
Okay, now lets get onto the pawn scripting part. For this tutorial I will be using DCMD.
If you are unfamiliar with DCMD, there is a tutorial about it here: http://forum.sa-mp.com/index.php?topic=75000.0
First we must change our includes and add 2 defines. If you use DUDB, comment or delete the: #include <DUDB>
At the top of your script add:
#include <ACC>
#define COLOR_SUCCESS 0x64F600FF
#define COLOR_RED 0xFF0000FF
You can change those colors to whatever you want, just have them defined, or change it in the script.
Now we start with the register command. We add it into OnPlayerCommandText:
pawn Код:
dcmd(register,8,cmdtext);
pawn Код:
dcmd_register(playerid, params[])
{
return 1;
}
pawn Код:
dcmd_register(playerid, params[])
{
new PlayerName[24]; // Create an array with the size of 24 to store the name in.
GetPlayerName(playerid, PlayerName, 24); // Store the name to the PlayerName array.
if(!AccountExists(PlayerName)) // Check if the account exists.
{
}
else if(AccountGetInt(PlayerName, "LoggedIn") == 0) return SendClientMessage(playerid, COLOR_RED, "Account already exists. Please use /login password to login.");
else return SendClientMessage(playerid, COLOR_RED, "You are already logged on!");
return 1;
}
First, we create a spot to put the players current username. We then get the name and store it in that spot. We ask the server if the account doesn't exist, than continue. Otherwise it will go down to the end of the } and to the else's. Some people get confused with the else's. Basically all we are doing is if it finds the account does exist, it will skip down there for further instruction. The first one says if they are not logged on, (the vlaue "LoggedOn" we will set later) send them a message saying their account already exists and to use /login password to login to their account. Than the second else is called if the first one isn't true. Basically it means if they are logged on. In order to be logged on they must have an account already so it just tells them that they are already logged on.
Now let's move onto the core:
First we will check a few things on their password..
pawn Код:
dcmd_register(playerid, params[])
{
new PlayerName[24]; // Create an array with the size of 24 to store the name in.
GetPlayerName(playerid, PlayerName, 24); // Store the name to the PlayerName array.
if(!AccountExists(PlayerName)) // Check if the account exists.
{
if(!strlen(params)) return SendClientMessage(playerid, COLOR_RED, "/register password [Password is CaSE SeNSiTivE]");
if(strlen(params) > 20) return SendClientMessage(playerid, COLOR_RED, "Password cannot be greater than 20 characters.");
if(strlen(params) < 3) return SendClientMessage(playerid, COLOR_RED, "Password cannot be less than 3 characters.");
}
else if(AccountGetInt(PlayerName, "LoggedIn") == 0) return SendClientMessage(playerid, COLOR_RED, "Account already exists. Please use /login password to login.");
else return SendClientMessage(playerid, COLOR_RED, "You are already logged on!");
return 1;
}
Alright, so now we are ready to create their account with their password and set some data.
pawn Код:
dcmd_register(playerid, params[])
{
new PlayerName[24]; // Create an array with the size of 24 to store the name in.
GetPlayerName(playerid, PlayerName, 24); // Store the name to the PlayerName array.
if(!AccountExists(PlayerName)) // Check if the account exists.
{
if(!strlen(params)) return SendClientMessage(playerid, COLOR_RED, "/register password [Password is CaSE SeNSiTivE]");
if(strlen(params) > 20) return SendClientMessage(playerid, COLOR_RED, "Password cannot be greater than 20 characters.");
if(strlen(params) < 3) return SendClientMessage(playerid, COLOR_RED, "Password cannot be less than 3 characters.");
new str[31];
format(str, sizeof(str), "%s/password", PlayerName);
new buf[145];
WP_Hash(buf, sizeof(buf), params);
djSet("accounts.json",str,buf);
AccountSetInt(PlayerName, "LoggedIn",0);
AccountSet(PlayerName, "password", buf);
printf("[REGISTER] %s - %s [%s]",PlayerName, IP, DayString);
SendClientMessage(playerid, COLOR_SUCCESS, "You have successfully registered! You may now use /login password to login.");
}
else if(AccountGetInt(PlayerName, "LoggedIn") == 0) return SendClientMessage(playerid, COLOR_RED, "Account already exists. Please use /login password to login.");
else return SendClientMessage(playerid, COLOR_RED, "You are already logged on!");
return 1;
}
Let's take a look and see what we are doing here.
First, we create a spot to store something for DJson. For this i'm using the actual DJson functions, not the include functions. str is just short for string here. Now we format some text into here. What you see here is %s/password %s stands for string, which means we are putting a string into there. In this case it's the name of the player. As seen in the diagram above, we submit the PlayerName(username) as the first category, than the key is password which we set in a moment. So now we have the location ready. Now we will take the password they submitted into the command and encrypt it into a cryptographic code. In layman's terms: a secret code that nobody can read. We create a buf with the length of 145. 145 is the minimum amount that Whirlpool. Whenever using the Whirlpool for passwords in your script you should keep it consistent. I suggest just using 145. Buf is just what we are storing the secret code to. WP_Hash is a function included with ******'s Whirlpool plugin, used to encrypt text. In this case our text is the information they submitted which we now know is stored in params.
Now we will set the password in their account, BUT WAIT! We never did any Create account thingy!! Don't worry, DJson will automatically create it. So now we have set the password to their account. Now we set two more things, the LoggedIn value, which we set to 0, and I set the password again to make sure it was set. And we send a message to them saying they have successfully been registered and that you can now use /login to login.
Alright, were done with the registration command, bathroom break!
Continued below because I couldn't fit everything within the 20000 character limit