Merge: New map directory structure and player passwords

This commit is contained in:
Perttu Ahola 2011-05-21 01:11:58 +03:00
commit 76e241392d
21 changed files with 680 additions and 82 deletions

@ -95,6 +95,8 @@ set(minetest_SRCS
tile.cpp tile.cpp
game.cpp game.cpp
main.cpp main.cpp
sha1.cpp
base64.cpp
) )
# Server sources # Server sources

123
src/base64.cpp Normal file

@ -0,0 +1,123 @@
/*
base64.cpp and base64.h
Copyright (C) 2004-2008 René Nyffenegger
This source code is provided 'as-is', without any express or implied
warranty. In no event will the author be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this source code must not be misrepresented; you must not
claim that you wrote the original source code. If you use this source code
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original source code.
3. This notice may not be removed or altered from any source distribution.
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
*/
#include "base64.h"
#include <iostream>
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static inline bool is_base64(unsigned char c) {
return (isalnum(c) || (c == '+') || (c == '/'));
}
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
std::string ret;
int i = 0;
int j = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4];
while (in_len--) {
char_array_3[i++] = *(bytes_to_encode++);
if (i == 3) {
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for(i = 0; (i <4) ; i++)
ret += base64_chars[char_array_4[i]];
i = 0;
}
}
if (i)
{
for(j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; (j < i + 1); j++)
ret += base64_chars[char_array_4[j]];
while((i++ < 3))
ret += '=';
}
return ret;
}
std::string base64_decode(std::string const& encoded_string) {
int in_len = encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
unsigned char char_array_4[4], char_array_3[3];
std::string ret;
while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
char_array_4[i++] = encoded_string[in_]; in_++;
if (i ==4) {
for (i = 0; i <4; i++)
char_array_4[i] = base64_chars.find(char_array_4[i]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (i = 0; (i < 3); i++)
ret += char_array_3[i];
i = 0;
}
}
if (i) {
for (j = i; j <4; j++)
char_array_4[j] = 0;
for (j = 0; j <4; j++)
char_array_4[j] = base64_chars.find(char_array_4[j]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
}
return ret;
}

4
src/base64.h Normal file

@ -0,0 +1,4 @@
#include <string>
std::string base64_encode(unsigned char const* , unsigned int len);
std::string base64_decode(std::string const& s);

@ -68,6 +68,7 @@ void * MeshUpdateThread::Thread()
Client::Client( Client::Client(
IrrlichtDevice *device, IrrlichtDevice *device,
const char *playername, const char *playername,
std::string password,
MapDrawControl &control): MapDrawControl &control):
m_mesh_update_thread(), m_mesh_update_thread(),
m_env( m_env(
@ -83,7 +84,9 @@ Client::Client(
m_server_ser_ver(SER_FMT_VER_INVALID), m_server_ser_ver(SER_FMT_VER_INVALID),
m_inventory_updated(false), m_inventory_updated(false),
m_time_of_day(0), m_time_of_day(0),
m_map_seed(0) m_map_seed(0),
m_password(password),
m_access_denied(false)
{ {
m_packetcounter_timer = 0.0; m_packetcounter_timer = 0.0;
m_delete_unused_sectors_timer = 0.0; m_delete_unused_sectors_timer = 0.0;
@ -299,11 +302,14 @@ void Client::step(float dtime)
// [0] u16 TOSERVER_INIT // [0] u16 TOSERVER_INIT
// [2] u8 SER_FMT_VER_HIGHEST // [2] u8 SER_FMT_VER_HIGHEST
// [3] u8[20] player_name // [3] u8[20] player_name
SharedBuffer<u8> data(2+1+PLAYERNAME_SIZE); // [23] u8[28] password
SharedBuffer<u8> data(2+1+PLAYERNAME_SIZE+PASSWORD_SIZE);
writeU16(&data[0], TOSERVER_INIT); writeU16(&data[0], TOSERVER_INIT);
writeU8(&data[2], SER_FMT_VER_HIGHEST); writeU8(&data[2], SER_FMT_VER_HIGHEST);
memset((char*)&data[3], 0, PLAYERNAME_SIZE); memset((char*)&data[3], 0, PLAYERNAME_SIZE);
snprintf((char*)&data[3], PLAYERNAME_SIZE, "%s", myplayer->getName()); snprintf((char*)&data[3], PLAYERNAME_SIZE, "%s", myplayer->getName());
snprintf((char*)&data[23], PASSWORD_SIZE, "%s", m_password.c_str());
// Send as unreliable // Send as unreliable
Send(0, data, false); Send(0, data, false);
} }
@ -598,6 +604,15 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
return; return;
} }
if(command == TOCLIENT_ACCESS_DENIED)
{
// The server didn't like our password. Note, this needs
// to be processed even if the serialisation format has
// not been agreed yet, the same as TOCLIENT_INIT.
m_access_denied = true;
return;
}
if(ser_version == SER_FMT_VER_INVALID) if(ser_version == SER_FMT_VER_INVALID)
{ {
dout_client<<DTIME<<"WARNING: Client: Server serialization" dout_client<<DTIME<<"WARNING: Client: Server serialization"

@ -207,6 +207,7 @@ public:
Client( Client(
IrrlichtDevice *device, IrrlichtDevice *device,
const char *playername, const char *playername,
std::string password,
MapDrawControl &control MapDrawControl &control
); );
@ -377,6 +378,11 @@ public:
// Get event from queue. CE_NONE is returned if queue is empty. // Get event from queue. CE_NONE is returned if queue is empty.
ClientEvent getClientEvent(); ClientEvent getClientEvent();
inline bool accessDenied()
{
return m_access_denied;
}
private: private:
// Virtual methods from con::PeerHandler // Virtual methods from con::PeerHandler
@ -430,6 +436,9 @@ private:
// The seed returned by the server in TOCLIENT_INIT is stored here // The seed returned by the server in TOCLIENT_INIT is stored here
u64 m_map_seed; u64 m_map_seed;
std::string m_password;
bool m_access_denied;
InventoryContext m_inventory_context; InventoryContext m_inventory_context;
Queue<ClientEvent> m_client_event_queue; Queue<ClientEvent> m_client_event_queue;

@ -150,6 +150,11 @@ enum ToClientCommand
f1000 player pitch f1000 player pitch
f1000 player yaw f1000 player yaw
*/ */
TOCLIENT_ACCESS_DENIED = 0x35,
/*
u16 command
*/
}; };
enum ToServerCommand enum ToServerCommand
@ -161,6 +166,7 @@ enum ToServerCommand
[0] u16 TOSERVER_INIT [0] u16 TOSERVER_INIT
[2] u8 SER_FMT_VER_HIGHEST [2] u8 SER_FMT_VER_HIGHEST
[3] u8[20] player_name [3] u8[20] player_name
[23] u8[28] password
*/ */
TOSERVER_INIT2 = 0x11, TOSERVER_INIT2 = 0x11,

@ -290,5 +290,24 @@ bool RecursiveDeleteContent(std::string path)
return true; return true;
} }
bool CreateAllDirs(std::string path)
{
size_t pos;
std::vector<std::string> tocreate;
std::string basepath = path;
while(!PathExists(basepath))
{
tocreate.push_back(basepath);
pos = basepath.rfind('/');
if(pos == std::string::npos)
return false;
basepath = basepath.substr(0,pos);
}
for(int i=tocreate.size()-1;i>=0;i--)
CreateDir(tocreate[i]);
return true;
}
} // namespace fs } // namespace fs

@ -38,6 +38,9 @@ std::vector<DirListNode> GetDirListing(std::string path);
// Returns true if already exists // Returns true if already exists
bool CreateDir(std::string path); bool CreateDir(std::string path);
// Create all directories on the given path that don't already exist.
bool CreateAllDirs(std::string path);
bool PathExists(std::string path); bool PathExists(std::string path);
// Only pass full paths to this one. True on success. // Only pass full paths to this one. True on success.

@ -634,6 +634,7 @@ void the_game(
gui::IGUIFont* font, gui::IGUIFont* font,
std::string map_dir, std::string map_dir,
std::string playername, std::string playername,
std::string password,
std::string address, std::string address,
u16 port, u16 port,
std::wstring &error_message std::wstring &error_message
@ -672,7 +673,6 @@ void the_game(
guienv->drawAll(); guienv->drawAll();
driver->endScene(); driver->endScene();
std::cout<<DTIME<<"Creating server and client"<<std::endl;
/* /*
Create server. Create server.
@ -680,6 +680,7 @@ void the_game(
*/ */
SharedPtr<Server> server; SharedPtr<Server> server;
if(address == ""){ if(address == ""){
std::cout<<DTIME<<"Creating server"<<std::endl;
server = new Server(map_dir); server = new Server(map_dir);
server->start(port); server->start(port);
} }
@ -688,7 +689,8 @@ void the_game(
Create client Create client
*/ */
Client client(device, playername.c_str(), draw_control); std::cout<<DTIME<<"Creating client"<<std::endl;
Client client(device, playername.c_str(), password, draw_control);
Address connect_address(0,0,0,0, port); Address connect_address(0,0,0,0, port);
try{ try{
@ -727,6 +729,10 @@ void the_game(
could_connect = true; could_connect = true;
break; break;
} }
if(client.accessDenied())
{
break;
}
// Wait for 10 seconds // Wait for 10 seconds
if(time_counter >= 10.0) if(time_counter >= 10.0)
{ {
@ -755,8 +761,16 @@ void the_game(
if(could_connect == false) if(could_connect == false)
{ {
std::cout<<DTIME<<"Timed out."<<std::endl; if(client.accessDenied())
{
error_message = L"Access denied. Check your password and try again.";
std::cout<<DTIME<<"Access denied."<<std::endl;
}
else
{
error_message = L"Connection timed out."; error_message = L"Connection timed out.";
std::cout<<DTIME<<"Timed out."<<std::endl;
}
gui_loadingtext->remove(); gui_loadingtext->remove();
return; return;
} }

@ -67,6 +67,7 @@ void the_game(
gui::IGUIFont* font, gui::IGUIFont* font,
std::string map_dir, std::string map_dir,
std::string playername, std::string playername,
std::string password,
std::string address, std::string address,
u16 port, u16 port,
std::wstring &error_message std::wstring &error_message

@ -164,30 +164,38 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
//t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT); //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
} }
// Nickname // Nickname + password
{ {
core::rect<s32> rect(0, 0, 100, 20); core::rect<s32> rect(0, 0, 110, 20);
rect += topleft_client + v2s32(40, 50+6); rect += topleft_client + v2s32(35, 50+6);
const wchar_t *text = L"Nickname"; const wchar_t *text = L"Name/Password";
Environment->addStaticText(text, rect, false, true, this, -1); Environment->addStaticText(text, rect, false, true, this, -1);
} }
{ {
core::rect<s32> rect(0, 0, 250, 30); core::rect<s32> rect(0, 0, 230, 30);
rect += topleft_client + v2s32(160, 50); rect += topleft_client + v2s32(160, 50);
gui::IGUIElement *e = gui::IGUIElement *e =
Environment->addEditBox(text_name.c_str(), rect, true, this, 258); Environment->addEditBox(text_name.c_str(), rect, true, this, 258);
if(text_name == L"") if(text_name == L"")
Environment->setFocus(e); Environment->setFocus(e);
} }
{
core::rect<s32> rect(0, 0, 120, 30);
rect += topleft_client + v2s32(size_client.X-60-100, 50);
gui::IGUIEditBox *e =
Environment->addEditBox(L"", rect, true, this, 264);
e->setPasswordBox(true);
}
// Address + port // Address + port
{ {
core::rect<s32> rect(0, 0, 100, 20); core::rect<s32> rect(0, 0, 110, 20);
rect += topleft_client + v2s32(40, 100+6); rect += topleft_client + v2s32(35, 100+6);
const wchar_t *text = L"Address + Port"; const wchar_t *text = L"Address/Port";
Environment->addStaticText(text, rect, false, true, this, -1); Environment->addStaticText(text, rect, false, true, this, -1);
} }
{ {
core::rect<s32> rect(0, 0, 250, 30); core::rect<s32> rect(0, 0, 230, 30);
rect += topleft_client + v2s32(160, 100); rect += topleft_client + v2s32(160, 100);
gui::IGUIElement *e = gui::IGUIElement *e =
Environment->addEditBox(text_address.c_str(), rect, true, this, 256); Environment->addEditBox(text_address.c_str(), rect, true, this, 256);
@ -195,9 +203,9 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
Environment->setFocus(e); Environment->setFocus(e);
} }
{ {
core::rect<s32> rect(0, 0, 100, 30); core::rect<s32> rect(0, 0, 120, 30);
//rect += topleft_client + v2s32(160+250+20, 125); //rect += topleft_client + v2s32(160+250+20, 125);
rect += topleft_client + v2s32(size_client.X-40-100, 100); rect += topleft_client + v2s32(size_client.X-60-100, 100);
Environment->addEditBox(text_port.c_str(), rect, true, this, 257); Environment->addEditBox(text_port.c_str(), rect, true, this, 257);
} }
{ {
@ -208,13 +216,13 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
} }
{ {
core::rect<s32> rect(0, 0, 250, 30); core::rect<s32> rect(0, 0, 250, 30);
rect += topleft_client + v2s32(40, 150); rect += topleft_client + v2s32(35, 150);
Environment->addCheckBox(fancy_trees, rect, this, 263, Environment->addCheckBox(fancy_trees, rect, this, 263,
L"Fancy trees"); L"Fancy trees");
} }
{ {
core::rect<s32> rect(0, 0, 250, 30); core::rect<s32> rect(0, 0, 250, 30);
rect += topleft_client + v2s32(40, 150+30); rect += topleft_client + v2s32(35, 150+30);
Environment->addCheckBox(smooth_lighting, rect, this, 262, Environment->addCheckBox(smooth_lighting, rect, this, 262,
L"Smooth Lighting"); L"Smooth Lighting");
} }
@ -245,12 +253,12 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
// Server parameters // Server parameters
{ {
core::rect<s32> rect(0, 0, 250, 30); core::rect<s32> rect(0, 0, 250, 30);
rect += topleft_server + v2s32(40, 30); rect += topleft_server + v2s32(35, 30);
Environment->addCheckBox(creative_mode, rect, this, 259, L"Creative Mode"); Environment->addCheckBox(creative_mode, rect, this, 259, L"Creative Mode");
} }
{ {
core::rect<s32> rect(0, 0, 250, 30); core::rect<s32> rect(0, 0, 250, 30);
rect += topleft_server + v2s32(40, 60); rect += topleft_server + v2s32(35, 60);
Environment->addCheckBox(enable_damage, rect, this, 261, L"Enable Damage"); Environment->addCheckBox(enable_damage, rect, this, 261, L"Enable Damage");
} }
// Map delete button // Map delete button
@ -296,6 +304,11 @@ void GUIMainMenu::acceptInput()
if(e != NULL) if(e != NULL)
m_data->name = e->getText(); m_data->name = e->getText();
} }
{
gui::IGUIElement *e = getElementFromId(264);
if(e != NULL)
m_data->password = e->getText();
}
{ {
gui::IGUIElement *e = getElementFromId(256); gui::IGUIElement *e = getElementFromId(256);
if(e != NULL) if(e != NULL)
@ -380,7 +393,7 @@ bool GUIMainMenu::OnEvent(const SEvent& event)
{ {
switch(event.GUIEvent.Caller->getID()) switch(event.GUIEvent.Caller->getID())
{ {
case 256: case 257: case 258: case 256: case 257: case 258: case 264:
acceptInput(); acceptInput();
quitMenu(); quitMenu();
return true; return true;

@ -46,6 +46,7 @@ struct MainMenuData
std::wstring address; std::wstring address;
std::wstring port; std::wstring port;
std::wstring name; std::wstring name;
std::wstring password;
bool fancy_trees; bool fancy_trees;
bool smooth_lighting; bool smooth_lighting;
// Server options // Server options

@ -325,6 +325,8 @@ Making it more portable:
#include "materials.h" #include "materials.h"
#include "game.h" #include "game.h"
#include "keycode.h" #include "keycode.h"
#include "sha1.h"
#include "base64.h"
// This makes textures // This makes textures
ITextureSource *g_texturesource = NULL; ITextureSource *g_texturesource = NULL;
@ -1170,6 +1172,7 @@ int main(int argc, char *argv[])
return 0; return 0;
} }
/* /*
More parameters More parameters
*/ */
@ -1324,11 +1327,15 @@ int main(int argc, char *argv[])
*/ */
std::wstring error_message = L""; std::wstring error_message = L"";
// The password entered during the menu screen,
std::string password;
/* /*
Menu-game loop Menu-game loop
*/ */
while(device->run() && kill == false) while(device->run() && kill == false)
{ {
// This is used for catching disconnects // This is used for catching disconnects
try try
{ {
@ -1428,6 +1435,26 @@ int main(int argc, char *argv[])
} }
playername = wide_to_narrow(menudata.name); playername = wide_to_narrow(menudata.name);
// Get an sha-1 hash of the player's name combined with
// the password entered. That's what the server uses as
// their password. (Exception : if the password field is
// blank, we send a blank password - this is for backwards
// compatibility with password-less players).
if(menudata.password.length() > 0)
{
std::string slt=playername + wide_to_narrow(menudata.password);
SHA1 *sha1 = new SHA1();
sha1->addBytes(slt.c_str(), slt.length());
unsigned char *digest = sha1->getDigest();
password = base64_encode(digest, 20);
free(digest);
}
else
{
password = "";
}
address = wide_to_narrow(menudata.address); address = wide_to_narrow(menudata.address);
int newport = stoi(wide_to_narrow(menudata.port)); int newport = stoi(wide_to_narrow(menudata.port));
if(newport != 0) if(newport != 0)
@ -1474,6 +1501,7 @@ int main(int argc, char *argv[])
font, font,
map_dir, map_dir,
playername, playername,
password,
address, address,
port, port,
error_message error_message

@ -4875,9 +4875,9 @@ plan_b:
return (s16)level; return (s16)level;
} }
void ServerMap::createDir(std::string path) void ServerMap::createDirs(std::string path)
{ {
if(fs::CreateDir(path) == false) if(fs::CreateAllDirs(path) == false)
{ {
m_dout<<DTIME<<"ServerMap: Failed to create directory " m_dout<<DTIME<<"ServerMap: Failed to create directory "
<<"\""<<path<<"\""<<std::endl; <<"\""<<path<<"\""<<std::endl;
@ -4885,29 +4885,52 @@ void ServerMap::createDir(std::string path)
} }
} }
std::string ServerMap::getSectorSubDir(v2s16 pos) std::string ServerMap::getSectorDir(v2s16 pos, int layout)
{ {
char cc[9]; char cc[9];
switch(layout)
{
case 1:
snprintf(cc, 9, "%.4x%.4x", snprintf(cc, 9, "%.4x%.4x",
(unsigned int)pos.X&0xffff, (unsigned int)pos.X&0xffff,
(unsigned int)pos.Y&0xffff); (unsigned int)pos.Y&0xffff);
return std::string(cc); return m_savedir + "/sectors/" + cc;
} case 2:
snprintf(cc, 9, "%.3x/%.3x",
(unsigned int)pos.X&0xfff,
(unsigned int)pos.Y&0xfff);
std::string ServerMap::getSectorDir(v2s16 pos) return m_savedir + "/sectors2/" + cc;
{ default:
return m_savedir + "/sectors/" + getSectorSubDir(pos); assert(false);
}
} }
v2s16 ServerMap::getSectorPos(std::string dirname) v2s16 ServerMap::getSectorPos(std::string dirname)
{ {
if(dirname.size() != 8)
throw InvalidFilenameException("Invalid sector directory name");
unsigned int x, y; unsigned int x, y;
int r = sscanf(dirname.c_str(), "%4x%4x", &x, &y); int r;
if(r != 2) size_t spos = dirname.rfind('/') + 1;
throw InvalidFilenameException("Invalid sector directory name"); assert(spos != std::string::npos);
if(dirname.size() - spos == 8)
{
// Old layout
r = sscanf(dirname.substr(spos).c_str(), "%4x%4x", &x, &y);
}
else if(dirname.size() - spos == 3)
{
// New layout
r = sscanf(dirname.substr(spos-4).c_str(), "%3x/%3x", &x, &y);
// Sign-extend the 12 bit values up to 16 bits...
if(x&0x800) x|=0xF000;
if(y&0x800) y|=0xF000;
}
else
{
assert(false);
}
assert(r == 2);
v2s16 pos((s16)x, (s16)y); v2s16 pos((s16)x, (s16)y);
return pos; return pos;
} }
@ -5106,7 +5129,7 @@ void ServerMap::saveMapMeta()
<<"seed="<<m_seed<<", chunksize="<<m_chunksize <<"seed="<<m_seed<<", chunksize="<<m_chunksize
<<std::endl; <<std::endl;
createDir(m_savedir); createDirs(m_savedir);
std::string fullpath = m_savedir + "/map_meta.txt"; std::string fullpath = m_savedir + "/map_meta.txt";
std::ofstream os(fullpath.c_str(), std::ios_base::binary); std::ofstream os(fullpath.c_str(), std::ios_base::binary);
@ -5179,7 +5202,7 @@ void ServerMap::saveChunkMeta()
dstream<<"INFO: ServerMap::saveChunkMeta(): Saving metadata of " dstream<<"INFO: ServerMap::saveChunkMeta(): Saving metadata of "
<<count<<" chunks"<<std::endl; <<count<<" chunks"<<std::endl;
createDir(m_savedir); createDirs(m_savedir);
std::string fullpath = m_savedir + "/chunk_meta"; std::string fullpath = m_savedir + "/chunk_meta";
std::ofstream os(fullpath.c_str(), std::ios_base::binary); std::ofstream os(fullpath.c_str(), std::ios_base::binary);
@ -5267,10 +5290,8 @@ void ServerMap::saveSectorMeta(ServerMapSector *sector)
u8 version = SER_FMT_VER_HIGHEST; u8 version = SER_FMT_VER_HIGHEST;
// Get destination // Get destination
v2s16 pos = sector->getPos(); v2s16 pos = sector->getPos();
createDir(m_savedir);
createDir(m_savedir+"/sectors");
std::string dir = getSectorDir(pos); std::string dir = getSectorDir(pos);
createDir(dir); createDirs(dir);
std::string fullpath = dir + "/meta"; std::string fullpath = dir + "/meta";
std::ofstream o(fullpath.c_str(), std::ios_base::binary); std::ofstream o(fullpath.c_str(), std::ios_base::binary);
@ -5282,22 +5303,21 @@ void ServerMap::saveSectorMeta(ServerMapSector *sector)
sector->differs_from_disk = false; sector->differs_from_disk = false;
} }
MapSector* ServerMap::loadSectorMeta(std::string dirname) MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load)
{ {
DSTACK(__FUNCTION_NAME); DSTACK(__FUNCTION_NAME);
// Get destination // Get destination
v2s16 p2d = getSectorPos(dirname); v2s16 p2d = getSectorPos(sectordir);
std::string dir = m_savedir + "/sectors/" + dirname;
ServerMapSector *sector = NULL; ServerMapSector *sector = NULL;
std::string fullpath = dir + "/meta"; std::string fullpath = sectordir + "/meta";
std::ifstream is(fullpath.c_str(), std::ios_base::binary); std::ifstream is(fullpath.c_str(), std::ios_base::binary);
if(is.good() == false) if(is.good() == false)
{ {
// If the directory exists anyway, it probably is in some old // If the directory exists anyway, it probably is in some old
// format. Just go ahead and create the sector. // format. Just go ahead and create the sector.
if(fs::PathExists(dir)) if(fs::PathExists(sectordir))
{ {
dstream<<"ServerMap::loadSectorMeta(): Sector metafile " dstream<<"ServerMap::loadSectorMeta(): Sector metafile "
<<fullpath<<" doesn't exist but directory does." <<fullpath<<" doesn't exist but directory does."
@ -5307,12 +5327,16 @@ MapSector* ServerMap::loadSectorMeta(std::string dirname)
m_sectors.insert(p2d, sector); m_sectors.insert(p2d, sector);
} }
else else
{
throw FileNotGoodException("Cannot open sector metafile"); throw FileNotGoodException("Cannot open sector metafile");
} }
}
else else
{ {
sector = ServerMapSector::deSerialize sector = ServerMapSector::deSerialize
(is, this, p2d, m_sectors); (is, this, p2d, m_sectors);
if(save_after_load)
saveSectorMeta(sector);
} }
sector->differs_from_disk = false; sector->differs_from_disk = false;
@ -5323,14 +5347,31 @@ MapSector* ServerMap::loadSectorMeta(std::string dirname)
bool ServerMap::loadSectorFull(v2s16 p2d) bool ServerMap::loadSectorFull(v2s16 p2d)
{ {
DSTACK(__FUNCTION_NAME); DSTACK(__FUNCTION_NAME);
std::string sectorsubdir = getSectorSubDir(p2d);
MapSector *sector = NULL; MapSector *sector = NULL;
// The directory layout we're going to load from.
// 1 - original sectors/xxxxzzzz/
// 2 - new sectors2/xxx/zzz/
// If we load from anything but the latest structure, we will
// immediately save to the new one, and remove the old.
int loadlayout = 1;
std::string sectordir1 = getSectorDir(p2d, 1);
std::string sectordir;
if(fs::PathExists(sectordir1))
{
sectordir = sectordir1;
}
else
{
loadlayout = 2;
sectordir = getSectorDir(p2d, 2);
}
//JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
try{ try{
sector = loadSectorMeta(sectorsubdir); sector = loadSectorMeta(sectordir, loadlayout != 2);
} }
catch(InvalidFilenameException &e) catch(InvalidFilenameException &e)
{ {
@ -5349,7 +5390,7 @@ bool ServerMap::loadSectorFull(v2s16 p2d)
Load blocks Load blocks
*/ */
std::vector<fs::DirListNode> list2 = fs::GetDirListing std::vector<fs::DirListNode> list2 = fs::GetDirListing
(m_savedir+"/sectors/"+sectorsubdir); (sectordir);
std::vector<fs::DirListNode>::iterator i2; std::vector<fs::DirListNode>::iterator i2;
for(i2=list2.begin(); i2!=list2.end(); i2++) for(i2=list2.begin(); i2!=list2.end(); i2++)
{ {
@ -5357,16 +5398,25 @@ bool ServerMap::loadSectorFull(v2s16 p2d)
if(i2->dir) if(i2->dir)
continue; continue;
try{ try{
loadBlock(sectorsubdir, i2->name, sector); loadBlock(sectordir, i2->name, sector, loadlayout != 2);
} }
catch(InvalidFilenameException &e) catch(InvalidFilenameException &e)
{ {
// This catches unknown crap in directory // This catches unknown crap in directory
} }
} }
if(loadlayout != 2)
{
dstream<<"Sector converted to new layout - deleting "<<
sectordir1<<std::endl;
fs::RecursiveDelete(sectordir1);
}
return true; return true;
} }
void ServerMap::saveBlock(MapBlock *block) void ServerMap::saveBlock(MapBlock *block)
{ {
DSTACK(__FUNCTION_NAME); DSTACK(__FUNCTION_NAME);
@ -5386,12 +5436,9 @@ void ServerMap::saveBlock(MapBlock *block)
// Get destination // Get destination
v3s16 p3d = block->getPos(); v3s16 p3d = block->getPos();
v2s16 p2d(p3d.X, p3d.Z); v2s16 p2d(p3d.X, p3d.Z);
createDir(m_savedir);
createDir(m_savedir+"/sectors");
std::string dir = getSectorDir(p2d); std::string dir = getSectorDir(p2d);
createDir(dir); createDirs(dir);
// Block file is map/sectors/xxxxxxxx/xxxx
char cc[5]; char cc[5];
snprintf(cc, 5, "%.4x", (unsigned int)p3d.Y&0xffff); snprintf(cc, 5, "%.4x", (unsigned int)p3d.Y&0xffff);
std::string fullpath = dir + "/" + cc; std::string fullpath = dir + "/" + cc;
@ -5427,12 +5474,11 @@ void ServerMap::saveBlock(MapBlock *block)
block->resetChangedFlag(); block->resetChangedFlag();
} }
void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector) void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load)
{ {
DSTACK(__FUNCTION_NAME); DSTACK(__FUNCTION_NAME);
// Block file is map/sectors/xxxxxxxx/xxxx std::string fullpath = sectordir+"/"+blockfile;
std::string fullpath = m_savedir+"/sectors/"+sectordir+"/"+blockfile;
try{ try{
std::ifstream is(fullpath.c_str(), std::ios_base::binary); std::ifstream is(fullpath.c_str(), std::ios_base::binary);
@ -5496,7 +5542,7 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSecto
*/ */
// Save old format blocks in new format // Save old format blocks in new format
if(version < SER_FMT_VER_HIGHEST) if(version < SER_FMT_VER_HIGHEST || save_after_load)
{ {
saveBlock(block); saveBlock(block);
} }

@ -545,13 +545,9 @@ public:
Misc. helper functions for fiddling with directory and file Misc. helper functions for fiddling with directory and file
names when saving names when saving
*/ */
void createDir(std::string path); void createDirs(std::string path);
void createSaveDir();
// returns something like "xxxxxxxx"
std::string getSectorSubDir(v2s16 pos);
// returns something like "map/sectors/xxxxxxxx" // returns something like "map/sectors/xxxxxxxx"
std::string getSectorDir(v2s16 pos); std::string getSectorDir(v2s16 pos, int layout = 2);
std::string createSectorDir(v2s16 pos);
// dirname: final directory name // dirname: final directory name
v2s16 getSectorPos(std::string dirname); v2s16 getSectorPos(std::string dirname);
v3s16 getBlockPos(std::string sectordir, std::string blockfile); v3s16 getBlockPos(std::string sectordir, std::string blockfile);
@ -572,7 +568,7 @@ public:
// (no MapBlocks) // (no MapBlocks)
// DEPRECATED? Sectors have no metadata anymore. // DEPRECATED? Sectors have no metadata anymore.
void saveSectorMeta(ServerMapSector *sector); void saveSectorMeta(ServerMapSector *sector);
MapSector* loadSectorMeta(std::string dirname); MapSector* loadSectorMeta(std::string dirname, bool save_after_load);
// Full load of a sector including all blocks. // Full load of a sector including all blocks.
// returns true on success, false on failure. // returns true on success, false on failure.
@ -583,7 +579,7 @@ public:
void saveBlock(MapBlock *block); void saveBlock(MapBlock *block);
// This will generate a sector with getSector if not found. // This will generate a sector with getSector if not found.
void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector); void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load=false);
// For debug printing // For debug printing
virtual void PrintInfo(std::ostream &out); virtual void PrintInfo(std::ostream &out);

@ -87,6 +87,7 @@ Player::Player():
m_position(0,0,0) m_position(0,0,0)
{ {
updateName("<not set>"); updateName("<not set>");
updatePassword("");
resetInventory(); resetInventory();
} }
@ -145,6 +146,7 @@ void Player::serialize(std::ostream &os)
Settings args; Settings args;
args.setS32("version", 1); args.setS32("version", 1);
args.set("name", m_name); args.set("name", m_name);
args.set("password", m_password);
args.setFloat("pitch", m_pitch); args.setFloat("pitch", m_pitch);
args.setFloat("yaw", m_yaw); args.setFloat("yaw", m_yaw);
args.setV3F("position", m_position); args.setV3F("position", m_position);
@ -179,6 +181,10 @@ void Player::deSerialize(std::istream &is)
//args.getS32("version"); //args.getS32("version");
std::string name = args.get("name"); std::string name = args.get("name");
updateName(name.c_str()); updateName(name.c_str());
std::string password = "";
if(args.exists("password"))
password = args.get("password");
updatePassword(password.c_str());
m_pitch = args.getFloat("pitch"); m_pitch = args.getFloat("pitch");
m_yaw = args.getFloat("yaw"); m_yaw = args.getFloat("yaw");
m_position = args.getV3F("position"); m_position = args.getV3F("position");

@ -25,6 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "collision.h" #include "collision.h"
#define PLAYERNAME_SIZE 20 #define PLAYERNAME_SIZE 20
#define PASSWORD_SIZE 28 // Maximum password length. Allows for
// base64-encoded SHA-1.
#define PLAYERNAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.," #define PLAYERNAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.,"
@ -121,6 +123,16 @@ public:
return m_name; return m_name;
} }
virtual void updatePassword(const char *password)
{
snprintf(m_password, PASSWORD_SIZE, "%s", password);
}
const char * getPassword()
{
return m_password;
}
virtual bool isLocal() const = 0; virtual bool isLocal() const = 0;
virtual void updateLight(u8 light_at_pos) {}; virtual void updateLight(u8 light_at_pos) {};
@ -157,6 +169,7 @@ public:
protected: protected:
char m_name[PLAYERNAME_SIZE]; char m_name[PLAYERNAME_SIZE];
char m_password[PASSWORD_SIZE];
f32 m_pitch; f32 m_pitch;
f32 m_yaw; f32 m_yaw;
v3f m_speed; v3f m_speed;

@ -1734,8 +1734,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
// [0] u16 TOSERVER_INIT // [0] u16 TOSERVER_INIT
// [2] u8 SER_FMT_VER_HIGHEST // [2] u8 SER_FMT_VER_HIGHEST
// [3] u8[20] player_name // [3] u8[20] player_name
// [23] u8[28] password <--- can be sent without this, from old versions
if(datasize < 3) if(datasize < 2+1+PLAYERNAME_SIZE)
return; return;
derr_server<<DTIME<<"Server: Got TOSERVER_INIT from " derr_server<<DTIME<<"Server: Got TOSERVER_INIT from "
@ -1767,17 +1768,41 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
*/ */
// Get player name // Get player name
const u32 playername_size = 20; char playername[PLAYERNAME_SIZE];
char playername[playername_size]; for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
for(u32 i=0; i<playername_size-1; i++)
{ {
playername[i] = data[3+i]; playername[i] = data[3+i];
} }
playername[playername_size-1] = 0; playername[PLAYERNAME_SIZE-1] = 0;
// Get password
char password[PASSWORD_SIZE];
if(datasize == 2+1+PLAYERNAME_SIZE)
{
// old version - assume blank password
password[0] = 0;
}
else
{
for(u32 i=0; i<PASSWORD_SIZE-1; i++)
{
password[i] = data[23+i];
}
password[PASSWORD_SIZE-1] = 0;
}
Player *checkplayer = m_env.getPlayer(playername);
if(checkplayer != NULL && strcmp(checkplayer->getPassword(),password))
{
derr_server<<DTIME<<"Server: peer_id="<<peer_id
<<": supplied invalid password for "
<<playername<<std::endl;
SendAccessDenied(m_con, peer_id);
return;
}
// Get player // Get player
Player *player = emergePlayer(playername, "", peer_id); Player *player = emergePlayer(playername, password, peer_id);
//Player *player = m_env.getPlayer(peer_id);
/*{ /*{
// DEBUG: Test serialization // DEBUG: Test serialization
@ -3138,6 +3163,20 @@ void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
con.Send(peer_id, 0, data, true); con.Send(peer_id, 0, data, true);
} }
void Server::SendAccessDenied(con::Connection &con, u16 peer_id)
{
DSTACK(__FUNCTION_NAME);
std::ostringstream os(std::ios_base::binary);
writeU16(os, TOCLIENT_ACCESS_DENIED);
// Make data buffer
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
// Send as reliable
con.Send(peer_id, 0, data, true);
}
/* /*
Non-static send methods Non-static send methods
*/ */
@ -4052,8 +4091,7 @@ v3f findSpawnPos(ServerMap &map)
), BS); ), BS);
} }
Player *Server::emergePlayer(const char *name, const char *password, Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
u16 peer_id)
{ {
/* /*
Try to get an existing player Try to get an existing player
@ -4099,6 +4137,7 @@ Player *Server::emergePlayer(const char *name, const char *password,
//player->peer_id = PEER_ID_INEXISTENT; //player->peer_id = PEER_ID_INEXISTENT;
player->peer_id = peer_id; player->peer_id = peer_id;
player->updateName(name); player->updateName(name);
player->updatePassword(password);
/* /*
Set player position Set player position

@ -436,6 +436,7 @@ private:
*/ */
static void SendHP(con::Connection &con, u16 peer_id, u8 hp); static void SendHP(con::Connection &con, u16 peer_id, u8 hp);
static void SendAccessDenied(con::Connection &con, u16 peer_id);
/* /*
Non-static send methods Non-static send methods
@ -476,11 +477,12 @@ private:
/* /*
Get a player from memory or creates one. Get a player from memory or creates one.
If player is already connected, return NULL If player is already connected, return NULL
The password is not checked here - it is only used to
set the password if a new player is created.
Call with env and con locked. Call with env and con locked.
*/ */
Player *emergePlayer(const char *name, const char *password, Player *emergePlayer(const char *name, const char *password, u16 peer_id);
u16 peer_id);
/* /*
Update water pressure. Update water pressure.

207
src/sha1.cpp Normal file

@ -0,0 +1,207 @@
/* sha1.cpp
Copyright (c) 2005 Michael D. Leonhard
http://tamale.net/
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "sha1.h"
// print out memory in hexadecimal
void SHA1::hexPrinter( unsigned char* c, int l )
{
assert( c );
assert( l > 0 );
while( l > 0 )
{
printf( " %02x", *c );
l--;
c++;
}
}
// circular left bit rotation. MSB wraps around to LSB
Uint32 SHA1::lrot( Uint32 x, int bits )
{
return (x<<bits) | (x>>(32 - bits));
};
// Save a 32-bit unsigned integer to memory, in big-endian order
void SHA1::storeBigEndianUint32( unsigned char* byte, Uint32 num )
{
assert( byte );
byte[0] = (unsigned char)(num>>24);
byte[1] = (unsigned char)(num>>16);
byte[2] = (unsigned char)(num>>8);
byte[3] = (unsigned char)num;
}
// Constructor *******************************************************
SHA1::SHA1()
{
// make sure that the data type is the right size
assert( sizeof( Uint32 ) * 5 == 20 );
// initialize
H0 = 0x67452301;
H1 = 0xefcdab89;
H2 = 0x98badcfe;
H3 = 0x10325476;
H4 = 0xc3d2e1f0;
unprocessedBytes = 0;
size = 0;
}
// Destructor ********************************************************
SHA1::~SHA1()
{
// erase data
H0 = H1 = H2 = H3 = H4 = 0;
for( int c = 0; c < 64; c++ ) bytes[c] = 0;
unprocessedBytes = size = 0;
}
// process ***********************************************************
void SHA1::process()
{
assert( unprocessedBytes == 64 );
//printf( "process: " ); hexPrinter( bytes, 64 ); printf( "\n" );
int t;
Uint32 a, b, c, d, e, K, f, W[80];
// starting values
a = H0;
b = H1;
c = H2;
d = H3;
e = H4;
// copy and expand the message block
for( t = 0; t < 16; t++ ) W[t] = (bytes[t*4] << 24)
+(bytes[t*4 + 1] << 16)
+(bytes[t*4 + 2] << 8)
+ bytes[t*4 + 3];
for(; t< 80; t++ ) W[t] = lrot( W[t-3]^W[t-8]^W[t-14]^W[t-16], 1 );
/* main loop */
Uint32 temp;
for( t = 0; t < 80; t++ )
{
if( t < 20 ) {
K = 0x5a827999;
f = (b & c) | ((b ^ 0xFFFFFFFF) & d);//TODO: try using ~
} else if( t < 40 ) {
K = 0x6ed9eba1;
f = b ^ c ^ d;
} else if( t < 60 ) {
K = 0x8f1bbcdc;
f = (b & c) | (b & d) | (c & d);
} else {
K = 0xca62c1d6;
f = b ^ c ^ d;
}
temp = lrot(a,5) + f + e + W[t] + K;
e = d;
d = c;
c = lrot(b,30);
b = a;
a = temp;
//printf( "t=%d %08x %08x %08x %08x %08x\n",t,a,b,c,d,e );
}
/* add variables */
H0 += a;
H1 += b;
H2 += c;
H3 += d;
H4 += e;
//printf( "Current: %08x %08x %08x %08x %08x\n",H0,H1,H2,H3,H4 );
/* all bytes have been processed */
unprocessedBytes = 0;
}
// addBytes **********************************************************
void SHA1::addBytes( const char* data, int num )
{
assert( data );
assert( num > 0 );
// add these bytes to the running total
size += num;
// repeat until all data is processed
while( num > 0 )
{
// number of bytes required to complete block
int needed = 64 - unprocessedBytes;
assert( needed > 0 );
// number of bytes to copy (use smaller of two)
int toCopy = (num < needed) ? num : needed;
// Copy the bytes
memcpy( bytes + unprocessedBytes, data, toCopy );
// Bytes have been copied
num -= toCopy;
data += toCopy;
unprocessedBytes += toCopy;
// there is a full block
if( unprocessedBytes == 64 ) process();
}
}
// digest ************************************************************
unsigned char* SHA1::getDigest()
{
// save the message size
Uint32 totalBitsL = size << 3;
Uint32 totalBitsH = size >> 29;
// add 0x80 to the message
addBytes( "\x80", 1 );
unsigned char footer[64] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
// block has no room for 8-byte filesize, so finish it
if( unprocessedBytes > 56 )
addBytes( (char*)footer, 64 - unprocessedBytes);
assert( unprocessedBytes <= 56 );
// how many zeros do we need
int neededZeros = 56 - unprocessedBytes;
// store file size (in bits) in big-endian format
storeBigEndianUint32( footer + neededZeros , totalBitsH );
storeBigEndianUint32( footer + neededZeros + 4, totalBitsL );
// finish the final block
addBytes( (char*)footer, neededZeros + 8 );
// allocate memory for the digest bytes
unsigned char* digest = (unsigned char*)malloc( 20 );
// copy the digest bytes
storeBigEndianUint32( digest, H0 );
storeBigEndianUint32( digest + 4, H1 );
storeBigEndianUint32( digest + 8, H2 );
storeBigEndianUint32( digest + 12, H3 );
storeBigEndianUint32( digest + 16, H4 );
// return the digest
return digest;
}

51
src/sha1.h Normal file

@ -0,0 +1,51 @@
/* sha1.h
Copyright (c) 2005 Michael D. Leonhard
http://tamale.net/
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef SHA1_HEADER
typedef unsigned int Uint32;
class SHA1
{
private:
// fields
Uint32 H0, H1, H2, H3, H4;
unsigned char bytes[64];
int unprocessedBytes;
Uint32 size;
void process();
public:
SHA1();
~SHA1();
void addBytes( const char* data, int num );
unsigned char* getDigest();
// utility methods
static Uint32 lrot( Uint32 x, int bits );
static void storeBigEndianUint32( unsigned char* byte, Uint32 num );
static void hexPrinter( unsigned char* c, int l );
};
#define SHA1_HEADER
#endif