mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-10-06 00:30:10 -06:00
Bazaar/Protect : split hardware encription, client and server codes
git-svn-id: svn://ultimatepp.org/upp/trunk@6171 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
8f9bfcc8e3
commit
d1a78c5335
27 changed files with 392 additions and 36 deletions
319
bazaar/ProtectServer/ProtectDB.cpp
Normal file
319
bazaar/ProtectServer/ProtectDB.cpp
Normal file
|
|
@ -0,0 +1,319 @@
|
|||
#include "ProtectDB.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
#include <Sql/sch_schema.h>
|
||||
#include <Sql/sch_source.h>
|
||||
|
||||
ProtectDB::ProtectDB()
|
||||
{
|
||||
connected = false;
|
||||
upgraded = false;
|
||||
}
|
||||
|
||||
ProtectDB::~ProtectDB()
|
||||
{
|
||||
if(connected)
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
// connect/disconnect
|
||||
bool ProtectDB::Connect(void)
|
||||
{
|
||||
#ifndef flagUSE_SQLITE
|
||||
if(!session.Connect(userName, password, dbName, host))
|
||||
#else
|
||||
if(!session.Open(dbName))
|
||||
#endif
|
||||
return false;
|
||||
connected = true;
|
||||
SQL = session;
|
||||
|
||||
// upgrade database on first connect
|
||||
if(!upgraded)
|
||||
{
|
||||
SqlSchema sch(MY_SQL);
|
||||
All_Tables(sch);
|
||||
SqlPerformScript(sch.Upgrade());
|
||||
SqlPerformScript(sch.Attributes());
|
||||
SQL.ClearError();
|
||||
upgraded = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProtectDB::Disconnect(void)
|
||||
{
|
||||
if(!connected)
|
||||
return true;
|
||||
session.Close();
|
||||
connected = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// refresh connection
|
||||
bool ProtectDB::RefreshConnection(void)
|
||||
{
|
||||
Disconnect();
|
||||
return Connect();
|
||||
}
|
||||
|
||||
// get data -- email is the key -- non repeatable
|
||||
VectorMap<String, Value> ProtectDB::Get(String const &mail)
|
||||
{
|
||||
VectorMap<String, Value> res = Default();
|
||||
|
||||
if(!RefreshConnection())
|
||||
{
|
||||
Cerr() << "SQL Error -- Session expired\n";
|
||||
res.Clear();
|
||||
return res;
|
||||
}
|
||||
|
||||
for(int i = 0; i < 2; i++)
|
||||
{
|
||||
SQL * Select(SqlAll()).From(USERS).Where(EMAIL == mail);
|
||||
if(SQL.WasError())
|
||||
{
|
||||
if(!RefreshConnection())
|
||||
{
|
||||
Cerr() << "SQL Error : " << session.GetErrorCodeString() << "\n";
|
||||
res.Clear();
|
||||
return res;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
// we've unique key, so...
|
||||
if(SQL.Fetch())
|
||||
for(int i = 0; i < res.GetCount(); i++)
|
||||
res[i] = SQL[res.GetKey(i)];
|
||||
else
|
||||
{
|
||||
res.Clear();
|
||||
return res;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// set/append data
|
||||
bool ProtectDB::Set(VectorMap<String, Value> const &d)
|
||||
{
|
||||
String eMail = d.Get("EMAIL");
|
||||
|
||||
// fill missing fields with default values
|
||||
VectorMap<String, Value>data = Default(d);
|
||||
|
||||
|
||||
for(int i = 0; i < 2; i++)
|
||||
{
|
||||
SQL * Select(SqlAll()).From(USERS).Where(EMAIL == eMail);
|
||||
if(SQL.WasError())
|
||||
{
|
||||
Cerr() << "Trying to refresh connection...\n";
|
||||
if(!RefreshConnection())
|
||||
{
|
||||
Cerr() << "SQL Error : " << session.GetErrorCodeString() << "\n";
|
||||
return false;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
if(SQL.Fetch())
|
||||
{
|
||||
SQL * Update(USERS)
|
||||
(NAME , data.Get("NAME"))
|
||||
(SURNAME , data.Get("SURNAME"))
|
||||
(ADDRESS , data.Get("ADDRESS"))
|
||||
(TOWN , data.Get("TOWN"))
|
||||
(ZONE , data.Get("ZONE"))
|
||||
(COUNTRY , data.Get("COUNTRY"))
|
||||
(ZIP , data.Get("ZIP"))
|
||||
(CATHEGORY , data.Get("CATHEGORY"))
|
||||
(CF , data.Get("CF"))
|
||||
(PIVA , data.Get("PIVA"))
|
||||
(PHONE , data.Get("PHONE"))
|
||||
(FAX , data.Get("FAX"))
|
||||
(CELL , data.Get("CELL"))
|
||||
(LICENSES , data.Get("LICENSES"))
|
||||
(EXPIRATION , data.Get("EXPIRATION"))
|
||||
(ALLOWEDVERSION , data.Get("ALLOWEDVERSION"))
|
||||
(ACTIVATIONKEY , data.Get("ACTIVATIONKEY"))
|
||||
(REGISTRATIONDATE , data.Get("REGISTRATIONDATE"))
|
||||
(ACTIVATED , data.Get("ACTIVATED"))
|
||||
(ACTIVATIONDATE , data.Get("ACTIVATIONDATE"))
|
||||
(LASTCONNECTIONDATE , data.Get("LASTCONNECTIONDATE"))
|
||||
(TOTALCONNECTIONS , data.Get("TOTALCONNECTIONS"))
|
||||
(TOTALCONNECTIONTIME , data.Get("TOTALCONNECTIONTIME"))
|
||||
.Where(EMAIL == eMail);
|
||||
}
|
||||
else
|
||||
{
|
||||
SQL * Insert(USERS)
|
||||
(EMAIL , eMail)
|
||||
(NAME , data.Get("NAME"))
|
||||
(SURNAME , data.Get("SURNAME"))
|
||||
(ADDRESS , data.Get("ADDRESS"))
|
||||
(TOWN , data.Get("TOWN"))
|
||||
(ZONE , data.Get("ZONE"))
|
||||
(COUNTRY , data.Get("COUNTRY"))
|
||||
(ZIP , data.Get("ZIP"))
|
||||
(CATHEGORY , data.Get("CATHEGORY"))
|
||||
(CF , data.Get("CF"))
|
||||
(PIVA , data.Get("PIVA"))
|
||||
(PHONE , data.Get("PHONE"))
|
||||
(FAX , data.Get("FAX"))
|
||||
(CELL , data.Get("CELL"))
|
||||
(LICENSES , data.Get("LICENSES"))
|
||||
(EXPIRATION , data.Get("EXPIRATION"))
|
||||
(ALLOWEDVERSION , data.Get("ALLOWEDVERSION"))
|
||||
(ACTIVATIONKEY , data.Get("ACTIVATIONKEY"))
|
||||
(REGISTRATIONDATE , data.Get("REGISTRATIONDATE"))
|
||||
(ACTIVATED , data.Get("ACTIVATED"))
|
||||
(ACTIVATIONDATE , data.Get("ACTIVATIONDATE"))
|
||||
(LASTCONNECTIONDATE , data.Get("LASTCONNECTIONDATE"))
|
||||
(TOTALCONNECTIONS , data.Get("TOTALCONNECTIONS"))
|
||||
(TOTALCONNECTIONTIME , data.Get("TOTALCONNECTIONTIME"))
|
||||
;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// get default record
|
||||
VectorMap<String, Value> ProtectDB::Default(VectorMap<String, Value> const &base)
|
||||
{
|
||||
VectorMap<String, Value> res(base, 1);
|
||||
res.FindAdd("EMAIL", "");
|
||||
res.FindAdd("NAME", "");
|
||||
res.FindAdd("SURNAME", "");
|
||||
res.FindAdd("ADDRESS", "");
|
||||
res.FindAdd("TOWN", "");
|
||||
res.FindAdd("ZONE", "");
|
||||
res.FindAdd("COUNTRY", "");
|
||||
res.FindAdd("ZIP", "");
|
||||
res.FindAdd("CATHEGORY", 1);
|
||||
res.FindAdd("CF", "");
|
||||
res.FindAdd("PIVA", "");
|
||||
res.FindAdd("PHONE", "");
|
||||
res.FindAdd("FAX", "");
|
||||
res.FindAdd("CELL", "");
|
||||
res.FindAdd("LICENSES", 1);
|
||||
res.FindAdd("EXPIRATION", GetSysTime() + 24*60*60*30);
|
||||
res.FindAdd("ALLOWEDVERSION", "9999.9999.9999");
|
||||
res.FindAdd("ACTIVATIONKEY", "");
|
||||
res.FindAdd("REGISTRATIONDATE", GetSysTime());
|
||||
res.FindAdd("ACTIVATED", false);
|
||||
res.FindAdd("ACTIVATIONDATE", GetSysTime());
|
||||
res.FindAdd("LASTCONNECTIONDATE", GetSysTime());
|
||||
res.FindAdd("TOTALCONNECTIONS", 0);
|
||||
res.FindAdd("TOTALCONNECTIONTIME", 0);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// gets emails connected to e given MAC
|
||||
// empty Vector if still none
|
||||
Vector<String> ProtectDB::GetMACEMails(String const &mac)
|
||||
{
|
||||
Vector<String> res;
|
||||
|
||||
if(!RefreshConnection())
|
||||
{
|
||||
Cerr() << "SQL Error -- Session expired\n";
|
||||
res.Clear();
|
||||
return res;
|
||||
}
|
||||
|
||||
for(int i = 0; i < 2; i++)
|
||||
{
|
||||
SQL * Select(SqlAll()).From(MACS).Where(MAC == mac);
|
||||
if(SQL.WasError())
|
||||
{
|
||||
if(!RefreshConnection())
|
||||
{
|
||||
Cerr() << "SQL Error : " << session.GetErrorCodeString() << "\n";
|
||||
res.Clear();
|
||||
return res;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
// we've unique key, so...
|
||||
if(SQL.Fetch())
|
||||
{
|
||||
String mailStr = SQL["EMAILS"];
|
||||
res = Split(mailStr, ",", true);
|
||||
}
|
||||
else
|
||||
res.Clear();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// update (or creates) given MAC record with connected mail
|
||||
bool ProtectDB::UpdateMac(String const &mac, Vector<String> const &eMails)
|
||||
{
|
||||
// get all emails connected to this MAC
|
||||
Index<String>prevMails = GetMACEMails(mac);
|
||||
|
||||
|
||||
// check if mail is already there
|
||||
bool mustUpdate = false;
|
||||
for(int i = 0; i < eMails.GetCount(); i++)
|
||||
if(prevMails.Find(ToLower(eMails[i])) < 0)
|
||||
{
|
||||
mustUpdate = true;
|
||||
prevMails.Add(ToLower(eMails[i]));
|
||||
}
|
||||
|
||||
// if eMail was already there, just return true
|
||||
if(!mustUpdate)
|
||||
return true;
|
||||
|
||||
String mailList = Join(prevMails.PickKeys(), ",");
|
||||
for(int i = 0; i < 2; i++)
|
||||
{
|
||||
SQL * Select(SqlAll()).From(MACS).Where(MAC == mac);
|
||||
if(SQL.WasError())
|
||||
{
|
||||
Cerr() << "Trying to refresh connection...\n";
|
||||
if(!RefreshConnection())
|
||||
{
|
||||
Cerr() << "SQL Error : " << session.GetErrorCodeString() << "\n";
|
||||
return false;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
if(SQL.Fetch())
|
||||
{
|
||||
SQL * Update(MACS)
|
||||
(EMAILS , mailList)
|
||||
.Where(MAC == mac);
|
||||
}
|
||||
else
|
||||
{
|
||||
SQL * Insert(MACS)
|
||||
(MAC , mac)
|
||||
(EMAILS , mailList)
|
||||
;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
83
bazaar/ProtectServer/ProtectDB.h
Normal file
83
bazaar/ProtectServer/ProtectDB.h
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
#ifndef _Protect_ProtectDB_h_
|
||||
#define _Protect_ProtectDB_h_
|
||||
|
||||
#include <Core/Core.h>
|
||||
|
||||
#ifndef flagUSE_SQLITE
|
||||
#include <MySql/MySql.h>
|
||||
#else
|
||||
#include <plugin/sqlite3/Sqlite3.h>
|
||||
#endif
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
#ifndef flagUSE_SQLITE
|
||||
#define SCHEMADIALECT <MySql/MySqlSchema.h>
|
||||
#else
|
||||
#define SCHEMADIALECT <plugin/sqlite3/Sqlite3Schema.h>
|
||||
#endif
|
||||
#define MODEL <ProtectServer/ProtectDB.sch>
|
||||
#include "Sql/sch_header.h"
|
||||
|
||||
// encapsulation of Protect database
|
||||
class ProtectDB
|
||||
{
|
||||
private:
|
||||
|
||||
// host, db name, username and password
|
||||
String host;
|
||||
String dbName;
|
||||
String userName;
|
||||
String password;
|
||||
|
||||
// connected flag
|
||||
bool connected;
|
||||
|
||||
// database upgraded flag
|
||||
bool upgraded;
|
||||
|
||||
// database session
|
||||
#ifndef flagUSE_SQLITE
|
||||
MySqlSession session;
|
||||
#else
|
||||
Sqlite3Session session;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
|
||||
ProtectDB();
|
||||
~ProtectDB();
|
||||
|
||||
// setting of connection data
|
||||
ProtectDB &SetHost(String const &_host) { host = _host; return *this; }
|
||||
ProtectDB &SetDBName(String const &_dbName) { dbName = _dbName; return *this; }
|
||||
ProtectDB &SetUserName(String const &_name) { userName = _name; return *this; }
|
||||
ProtectDB &SetPassword(String const &_pwd) { password = _pwd; return *this; }
|
||||
|
||||
// connect/disconnect
|
||||
bool Connect(void);
|
||||
bool Disconnect(void);
|
||||
bool IsConnected(void) { return connected; }
|
||||
|
||||
// refresh connection
|
||||
bool RefreshConnection(void);
|
||||
|
||||
// get data -- email is the key -- non repeatable
|
||||
VectorMap<String, Value>Get(String const &mail);
|
||||
|
||||
// set/append data
|
||||
bool Set(VectorMap<String, Value> const &data);
|
||||
|
||||
// get default record
|
||||
VectorMap<String, Value> Default(VectorMap<String, Value> const &base = VectorMap<String, Value>());
|
||||
|
||||
// network adapter MAC checkings -- if enabled, avoid multiple demo
|
||||
// registrations with different mails on same machine(s)
|
||||
Vector<String> GetMACEMails(String const &mac);
|
||||
bool UpdateMac(String const &mac, Vector<String> const &eMails);
|
||||
};
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
#endif
|
||||
31
bazaar/ProtectServer/ProtectDB.sch
Normal file
31
bazaar/ProtectServer/ProtectDB.sch
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
TABLE_(USERS)
|
||||
STRING_ (EMAIL, 50) PRIMARY_KEY
|
||||
STRING_ (NAME, 200)
|
||||
STRING_ (SURNAME, 200)
|
||||
STRING_ (ADDRESS, 200)
|
||||
STRING_ (TOWN, 50)
|
||||
STRING_ (ZONE, 20)
|
||||
STRING_ (COUNTRY, 50)
|
||||
STRING_ (ZIP, 20)
|
||||
INT_ (CATHEGORY)
|
||||
STRING_ (CF, 50)
|
||||
STRING_ (PIVA, 50)
|
||||
STRING_ (PHONE, 50)
|
||||
STRING_ (FAX, 50)
|
||||
STRING_ (CELL, 50)
|
||||
TIME_ (EXPIRATION)
|
||||
INT_ (LICENSES)
|
||||
STRING_ (ALLOWEDVERSION, 20)
|
||||
STRING_ (ACTIVATIONKEY, 200)
|
||||
TIME_ (REGISTRATIONDATE)
|
||||
BOOL_ (ACTIVATED)
|
||||
TIME_ (ACTIVATIONDATE)
|
||||
TIME_ (LASTCONNECTIONDATE)
|
||||
INT_ (TOTALCONNECTIONS)
|
||||
INT_ (TOTALCONNECTIONTIME)
|
||||
END_TABLE
|
||||
|
||||
TABLE_(MACS)
|
||||
STRING_ (MAC, 17) PRIMARY_KEY
|
||||
STRING_ (EMAILS, 200)
|
||||
END_TABLE
|
||||
844
bazaar/ProtectServer/ProtectServer.cpp
Normal file
844
bazaar/ProtectServer/ProtectServer.cpp
Normal file
|
|
@ -0,0 +1,844 @@
|
|||
#include "ProtectServer.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
// email validation helper
|
||||
bool ValidateEMail(const char *address)
|
||||
{
|
||||
int count = 0;
|
||||
const char *c, *domain;
|
||||
static const char *rfc822_specials = "()<>@,;:\\\"[]";
|
||||
|
||||
// first we validate the name portion (name@domain)
|
||||
for (c = address; *c; c++)
|
||||
{
|
||||
if (*c == '\"' && (c == address || *(c - 1) == '.' || *(c - 1) == '\"'))
|
||||
{
|
||||
while (*++c)
|
||||
{
|
||||
if (*c == '\"')
|
||||
break;
|
||||
if (*c == '\\' && (*++c == ' '))
|
||||
continue;
|
||||
if (*c < ' ' || *c >= 127)
|
||||
return false;
|
||||
}
|
||||
if (!*c++)
|
||||
return false;
|
||||
if (*c == '@')
|
||||
break;
|
||||
if (*c != '.')
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
if (*c == '@')
|
||||
break;
|
||||
if (*c <= ' ' || *c >= 127)
|
||||
return false;
|
||||
if (strchr(rfc822_specials, *c))
|
||||
return false;
|
||||
}
|
||||
if (c == address || *(c - 1) == '.')
|
||||
return false;
|
||||
|
||||
// next we validate the domain portion (name@domain)
|
||||
if (!*(domain = ++c))
|
||||
return false;
|
||||
do
|
||||
{
|
||||
if (*c == '.')
|
||||
{
|
||||
if (c == domain || *(c - 1) == '.')
|
||||
return false;
|
||||
count++;
|
||||
}
|
||||
if (*c <= ' ' || *c >= 127)
|
||||
return false;
|
||||
if (strchr(rfc822_specials, *c))
|
||||
return false;
|
||||
}
|
||||
while (*++c);
|
||||
return (count >= 1);
|
||||
}
|
||||
|
||||
// constructor - defaults to port 8787 and connection timeout of 5 minutes (300 sec.)
|
||||
ProtectServer::ProtectServer(int port) : ScgiServer(port)
|
||||
{
|
||||
// setup default cypher
|
||||
cypher = new Snow2;
|
||||
|
||||
// client timeout defaults to 300 seconds (5 minutes)
|
||||
idCleanupTime = 300;
|
||||
|
||||
// database cleanup time -- default to 30 days (2592000 seconds)
|
||||
// used to clean up registrations with no activation on database
|
||||
dbCleanupTime = 2592000;
|
||||
|
||||
// initializes last cleanups times to now()
|
||||
lastIDCleanupTime = GetSysTime();
|
||||
lastDBCleanupTime = GetSysTime();
|
||||
|
||||
// no MAC handling by default
|
||||
recordMACs = false;
|
||||
checkExistingMAC = false;
|
||||
alertMACEMail = "";
|
||||
|
||||
// enforce MAC data from client by default
|
||||
enforceMAC = true;
|
||||
}
|
||||
|
||||
// generates an unique activation key composed by 20 random uppercase chars
|
||||
String ProtectServer::GenerateActivationKey(void)
|
||||
{
|
||||
String key;
|
||||
for(int i = 0; i < 20; i++)
|
||||
key << (char)(Random('Z' - 'A') + 'A');
|
||||
return key;
|
||||
}
|
||||
|
||||
// executes database cleanup
|
||||
void ProtectServer::DBCleanup(void)
|
||||
{
|
||||
// @@@ TO DO !!!
|
||||
Cerr() << "DB Cleanup :: TO DO\n";
|
||||
}
|
||||
|
||||
// polls clients and remove those which connection has expired
|
||||
void ProtectServer::CheckExpiredClients(void)
|
||||
{
|
||||
Time curTime = GetSysTime();
|
||||
for(int iClient = clientLinks.GetCount() - 1; iClient >= 0; iClient--)
|
||||
if(clientLinks[iClient].time < curTime)
|
||||
{
|
||||
String eMail = clientLinks[iClient].eMail;
|
||||
bool connected = clientLinks[iClient].connected;
|
||||
clientLinks.Remove(iClient);
|
||||
if(connected && registeredConnections.Find(eMail) >= 0)
|
||||
{
|
||||
registeredConnections.Get(eMail)--;
|
||||
if(registeredConnections.Get(eMail) <= 0)
|
||||
registeredConnections.RemoveKey(eMail);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// checks client list to see if a client is connected
|
||||
// and refresh its expire time on the way
|
||||
bool ProtectServer::IsClientConnected(dword clientID, String const &eMail)
|
||||
{
|
||||
int iClient = clientLinks.Find(clientID);
|
||||
if(iClient >= 0 && clientLinks[iClient].connected && clientLinks[iClient].eMail == eMail)
|
||||
{
|
||||
clientLinks[iClient].time = GetSysTime() + idCleanupTime;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// connects a client -- returns previous clientID or a new one if expired
|
||||
// doesn't check anything, that one must be done elsewhere
|
||||
dword ProtectServer::ConnectClient(String const &eMail, dword id)
|
||||
{
|
||||
// try to fetch id from active pool
|
||||
int iClient = clientLinks.Find(id);
|
||||
|
||||
// if not found in pool or ID allocated to another user, allocate a new one
|
||||
if(iClient < 0 || clientLinks[iClient].eMail != eMail)
|
||||
{
|
||||
// mark id as invalid
|
||||
iClient = -1;
|
||||
|
||||
// generate a new id
|
||||
do
|
||||
{
|
||||
id = Random();
|
||||
}
|
||||
while(id == 0 || id == (unsigned)-1 || clientLinks.Find(id) >= 0);
|
||||
}
|
||||
|
||||
// adds to clientLinks and to pool if needed, otherwise update record
|
||||
if(iClient < 0)
|
||||
{
|
||||
// a new client ID was generated, add it to pool, by now as non-connected one
|
||||
clientLinks.Add(id, TimeMail(GetSysTime() + idCleanupTime, eMail, false));
|
||||
iClient = clientLinks.GetCount() - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// no new ID was generated, client probably exited without disconnecting
|
||||
// just refresh its time and mark it as connected
|
||||
clientLinks[iClient].time = GetSysTime() + idCleanupTime;
|
||||
}
|
||||
|
||||
// if client marked as non connected, update connections count
|
||||
if(!clientLinks[iClient].connected)
|
||||
{
|
||||
clientLinks[iClient].connected = true;
|
||||
int i = registeredConnections.Find(eMail);
|
||||
if(i >= 0)
|
||||
registeredConnections[i]++;
|
||||
else
|
||||
registeredConnections.Add(eMail, 1);
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
// disconnects a client -- leaves id on pool up to expiration
|
||||
// updates count of clients connected by email
|
||||
void ProtectServer::DisconnectClient(dword clientID)
|
||||
{
|
||||
int i = clientLinks.Find(clientID);
|
||||
if(i >= 0)
|
||||
{
|
||||
String eMail = clientLinks[i].eMail;
|
||||
clientLinks[i].connected = false;
|
||||
i = registeredConnections.Find(eMail);
|
||||
if(i >= 0)
|
||||
{
|
||||
registeredConnections[i]--;
|
||||
if(registeredConnections[i] <= 0)
|
||||
registeredConnections.Remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// alert by email if user want to register for demo with an
|
||||
// already used MAC
|
||||
bool ProtectServer::SendMACAlert(String const &eMail, Vector<String> const &mails)
|
||||
{
|
||||
smtp.New();
|
||||
smtp.TimeSent(GetSysTime());
|
||||
smtp.To(alertMACEMail);
|
||||
smtp.Subject(t_("PROTECT SERVER : ATTEMPT TO REGISTER WITH EXPIRED MAC"));
|
||||
// smtp.From(serverVars.Get("SERVER_NAME"));
|
||||
String body = "Attempt to register with e-mail : " + eMail + "\n";
|
||||
body += "E-Mails connected to this one by MAC addresses :\n";
|
||||
for(int i = 0; i < mails.GetCount(); i++)
|
||||
body += mails[i] + "\n";
|
||||
smtp.Text(body, "text/plain; charset=utf-8");
|
||||
return smtp.Send();
|
||||
}
|
||||
|
||||
// process MAC list in data field
|
||||
// if 'registering' is true, returns false if MAC already there
|
||||
bool ProtectServer::ProcessMACList(String const &mail, String const &MACList, bool registering)
|
||||
{
|
||||
// gathered emails from all MACs
|
||||
Index<String>mailIndex;
|
||||
|
||||
// quick exit if we don't use MAC features...
|
||||
if(alertMACEMail.IsEmpty() && !checkExistingMAC && !recordMACs)
|
||||
return true;
|
||||
|
||||
// get vector of client's MACs
|
||||
Vector<String> macs = Split(MACList, ",", true);
|
||||
|
||||
// gather emails for each MAC and combine them
|
||||
bool found = false;
|
||||
for(int iMac = 0; iMac < macs.GetCount(); iMac++)
|
||||
{
|
||||
Vector<String>macEMails = db.GetMACEMails(macs[iMac]);
|
||||
if(macEMails.GetCount())
|
||||
{
|
||||
// we found at least an entry
|
||||
found = true;
|
||||
|
||||
// adds to customer registered mails list
|
||||
for(int i = 0; i < macEMails.GetCount(); i++)
|
||||
{
|
||||
if(mailIndex.Find(macEMails[i]) < 0)
|
||||
mailIndex.Add(macEMails[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add current email to MAC email list if needed
|
||||
if(mailIndex.Find(ToLower(mail)) < 0)
|
||||
mailIndex.Add(ToLower(mail));
|
||||
|
||||
// if we wanna record all customer's MACs, just do it
|
||||
// each MAC gets associated with full list of emails
|
||||
if(recordMACs)
|
||||
{
|
||||
for(int iMac = 0; iMac < macs.GetCount(); iMac++)
|
||||
db.UpdateMac(macs[iMac], mailIndex.GetKeys());
|
||||
}
|
||||
|
||||
// if we wanna be signaled by email, just do it
|
||||
if(!alertMACEMail.IsEmpty() && found && registering)
|
||||
SendMACAlert(mail, mailIndex.GetKeys());
|
||||
|
||||
// if we wanna drop all 'smart' people....
|
||||
if(checkExistingMAC && found && registering)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void ProtectServer::OnAccepted()
|
||||
{
|
||||
Cout() << "Accepted connection from client " << FormatIP(clientIP) << "\n";
|
||||
}
|
||||
|
||||
void ProtectServer::OnRequest()
|
||||
{
|
||||
int err = 0;
|
||||
VectorMap<String, Value> data;
|
||||
VectorMap<String, Value> results;
|
||||
String IV;
|
||||
|
||||
// we handle just POST requests, GET not allowed
|
||||
if(HasPostData())
|
||||
{
|
||||
// all requests besides PROTECT_ACTIVATE go through post
|
||||
if(post.Find("IV") < 0)
|
||||
err = PROTECT_MISSING_IV;
|
||||
else
|
||||
{
|
||||
IV = ScanHexString(post.GetString("IV"));
|
||||
if(post.Find("DATA") < 0)
|
||||
err = PROTECT_MISSING_DATA;
|
||||
else
|
||||
{
|
||||
cypher->SetKey(communicationKey, IV);
|
||||
String decoded = (*cypher)(ScanHexString(post.GetString("DATA")));
|
||||
LoadFromXML(data, decoded);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
err = PROTECT_BAD_REQUEST;
|
||||
|
||||
|
||||
// Get request reason and process it
|
||||
// supports following reasons :
|
||||
// CONNECT establish connection to server
|
||||
// DISCONNECT frees server connection
|
||||
// REFRESH refreshes server connection (to restart timeout)
|
||||
// GETKEY gets application key
|
||||
// REGISTER registers app for timed demo OR re-request activation code if already registered
|
||||
// GETLICENSEINFO gets info about license (name, expiration date, app version....)
|
||||
if(!err && data.Find("REASON") < 0)
|
||||
err = PROTECT_MISSING_REASON;
|
||||
if(!err && enforceMAC && data.Find("MAC") < 0)
|
||||
err = PROTECT_MISSING_MAC;
|
||||
if(!err)
|
||||
results = ProcessRequest(data.Get("REASON"), data);
|
||||
|
||||
// if previous error, sets it into result packet
|
||||
if(err)
|
||||
{
|
||||
results.Add("ERROR", err);
|
||||
results.Add("ERRORMSG", ProtectMessage(err));
|
||||
}
|
||||
else if(results.Find("ERROR") >= 0)
|
||||
results.Add("ERRORMSG", ProtectMessage(results.Get("ERROR")));
|
||||
|
||||
// encodes results and send back to client
|
||||
clientSock.Write("Content-Type: text/plain\r\n\r\n");
|
||||
cypher->SetKey(communicationKey);
|
||||
clientSock.Write("IV=" + HexString(cypher->GetNonce()) + "\r\n");
|
||||
String encoded = HexString((*cypher)(StoreAsXML(results, "ProtectServer")));
|
||||
clientSock.Write("DATA=" + encoded + "\r\n");
|
||||
}
|
||||
|
||||
void ProtectServer::OnClosed()
|
||||
{
|
||||
// do client and db cleanup if related times are expired
|
||||
// NOTE : db cleanup is time consuming -- DON'T put a short time !!
|
||||
// it would be maybe better to put it inside a separate thread/process ??
|
||||
Time now = GetSysTime();
|
||||
if(now - lastIDCleanupTime > idCleanupTime)
|
||||
CheckExpiredClients();
|
||||
if(now - lastDBCleanupTime > dbCleanupTime)
|
||||
DBCleanup();
|
||||
|
||||
Cout() << "Connection with " << FormatIP(clientIP) << " closed\n";
|
||||
}
|
||||
|
||||
// process client request
|
||||
// takes a VectorMap<String, Value> on input from client
|
||||
// produces a response VectorMap<String, Value> to be returned
|
||||
VectorMap<String, Value> ProtectServer::ProcessRequest(int reason, VectorMap<String, Value> const &v)
|
||||
{
|
||||
VectorMap<String, Value> res;
|
||||
dword clientID;
|
||||
VectorMap<String, Value> userRec;
|
||||
String eMail;
|
||||
String activationKey;
|
||||
int numConnections;
|
||||
|
||||
String locale;
|
||||
if(v.Find("LOCALE") >= 0)
|
||||
locale = v.Get("LOCALE");
|
||||
else
|
||||
locale = "EN-US";
|
||||
|
||||
switch(reason)
|
||||
{
|
||||
case PROTECT_REGISTER:
|
||||
{
|
||||
// we need an eMail to register
|
||||
if(v.Find("EMAIL") < 0)
|
||||
{
|
||||
res.Add("ERROR", PROTECT_MISSING_EMAIL);
|
||||
return res;
|
||||
}
|
||||
eMail = v.Get("EMAIL");
|
||||
if(!ValidateEMail(~eMail))
|
||||
{
|
||||
res.Add("ERROR", PROTECT_INVALID_EMAIL);
|
||||
return res;
|
||||
}
|
||||
|
||||
// MAC may or may not be present, depending on client
|
||||
// (old ones don't support it)
|
||||
// so, we can decide if accept MACless clients or not
|
||||
// this is already done on OnRequest handler, here we
|
||||
// just check MAC, *if* present
|
||||
bool denyRegistration = false;
|
||||
if(v.Find("MAC") >= 0 && !ProcessMACList(eMail, v.Get("MAC"), true))
|
||||
denyRegistration = true;
|
||||
|
||||
// avoid hacking of source packet stripping eventually
|
||||
// added licenseinfo, expiration, etc
|
||||
VectorMap<String, Value>vs(v, 1);
|
||||
vs.RemoveKey("LICENSES");
|
||||
vs.RemoveKey("EXPIRATION");
|
||||
vs.RemoveKey("ACTIVATIONKEY");
|
||||
vs.RemoveKey("REGISTRATIONDATE");
|
||||
vs.RemoveKey("ACTIVATED");
|
||||
vs.RemoveKey("ACTIVATIONDATE");
|
||||
vs.RemoveKey("LASTCONNECTIONDATE");
|
||||
vs.RemoveKey("TOTALCONNECTIONS");
|
||||
vs.RemoveKey("TOTALCONNECTIONTIME");
|
||||
|
||||
// try to get user record from database, if any
|
||||
userRec = db.Get(eMail);
|
||||
|
||||
// if not found, new registration
|
||||
if(!userRec.GetCount())
|
||||
{
|
||||
// drop 'smart' people....
|
||||
if(denyRegistration)
|
||||
{
|
||||
// signals expiration and leave
|
||||
res.Add("ERROR", PROTECT_MAIL_ALREADY_USED);
|
||||
return res;
|
||||
}
|
||||
|
||||
// generates activation key from email
|
||||
vs.Add("ACTIVATIONKEY", GenerateActivationKey());
|
||||
vs.Add("REGISTRATIONDATE", GetSysTime());
|
||||
vs.Add("ACTIVATED", false);
|
||||
vs.Add("ACTIVATIONDATE", GetSysTime()); // dummy, maybe not needed now
|
||||
vs.Add("LASTCONNECTIONDATE", GetSysTime()); // dummy, maybe not needed now
|
||||
vs.Add("TOTALCONNECTIONS", 0);
|
||||
vs.Add("TOTALCONNECTIONTIME", 0);
|
||||
|
||||
// add to database
|
||||
db.Set(vs);
|
||||
|
||||
// send the activation mail to user
|
||||
userRec = db.Get(eMail);
|
||||
if(SendActivationMail(userRec, locale))
|
||||
res.Add("STATUS", "ACTIVATION RESENT");
|
||||
else
|
||||
res.Add("ERROR", PROTECT_MAIL_SEND_ERROR);
|
||||
}
|
||||
// otherwise we shall check if license expired
|
||||
else if(userRec.Get("EXPIRATION") <= GetSysTime())
|
||||
{
|
||||
// signals expiration and leave
|
||||
res.Add("ERROR", PROTECT_MAIL_ALREADY_USED);
|
||||
}
|
||||
// otherwise, we shall send activation mail again
|
||||
// it may be same user on another machine
|
||||
else
|
||||
{
|
||||
// already registered but still not activated
|
||||
// resend activation mail
|
||||
if(SendActivationMail(userRec, locale))
|
||||
res.Add("STATUS", "ACTIVATION RESENT");
|
||||
else
|
||||
res.Add("ERROR", PROTECT_MAIL_SEND_ERROR);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PROTECT_CONNECT:
|
||||
{
|
||||
// we need email to connect
|
||||
if(v.Find("EMAIL") < 0)
|
||||
{
|
||||
res.Add("ERROR", PROTECT_MISSING_EMAIL);
|
||||
return res;
|
||||
}
|
||||
eMail = v.Get("EMAIL");
|
||||
|
||||
// we need previous clientID to connect, (or -1 if none)
|
||||
if(v.Find("CLIENTID") < 0)
|
||||
{
|
||||
res.Add("ERROR", PROTECT_MISSING_CLIENTID);
|
||||
return res;
|
||||
}
|
||||
clientID = (int)v.Get("CLIENTID");
|
||||
|
||||
// if already connected, just return ok
|
||||
if(IsClientConnected(clientID, eMail))
|
||||
return res;
|
||||
|
||||
// get the user data from database
|
||||
userRec = db.Get(eMail);
|
||||
|
||||
// if no mail data, product is unregistered
|
||||
if(!userRec.GetCount())
|
||||
{
|
||||
res.Add("ERROR", PROTECT_UNREGISTERED);
|
||||
return res;
|
||||
}
|
||||
|
||||
// product registered, we check for activation key
|
||||
if(v.Find("ACTIVATIONKEY") < 0)
|
||||
{
|
||||
res.Add("ERROR", PROTECT_MISSING_ACTIVATIONKEY);
|
||||
SendActivationMail(userRec, locale);
|
||||
return res;
|
||||
}
|
||||
|
||||
// check for activation key correctness
|
||||
if(v.Get("ACTIVATIONKEY") != userRec.Get("ACTIVATIONKEY"))
|
||||
{
|
||||
res.Add("ERROR", PROTECT_BAD_ACTIVATIONKEY);
|
||||
SendActivationMail(userRec, locale);
|
||||
return res;
|
||||
}
|
||||
|
||||
// ok, product registered and activated... is license expired ?
|
||||
if(userRec.Get("EXPIRATION") < GetSysTime())
|
||||
{
|
||||
res.Add("ERROR", PROTECT_LICENSE_EXPIRED);
|
||||
return res;
|
||||
}
|
||||
|
||||
// all ok, we shall finally check if number of licenses has overrun
|
||||
// first, we get number of current connections with same email
|
||||
numConnections = registeredConnections.Find(eMail);
|
||||
if(numConnections < 0)
|
||||
numConnections = 0;
|
||||
else
|
||||
numConnections = registeredConnections[numConnections];
|
||||
if(numConnections >= (int)userRec.Get("LICENSES"))
|
||||
{
|
||||
res.Add("ERROR", PROTECT_LICENSES_NUMBER_EXCEEDED);
|
||||
return res;
|
||||
}
|
||||
|
||||
// all OK, connect client and return connection ID
|
||||
clientID = ConnectClient(eMail, clientID);
|
||||
res.Add("CLIENTID", (int)clientID);
|
||||
|
||||
// mark product as activated in database, if needed
|
||||
if(!userRec.Get("ACTIVATED"))
|
||||
{
|
||||
userRec.Get("ACTIVATED") = true;
|
||||
userRec.Get("ACTIVATIONDATE") = GetSysTime();
|
||||
}
|
||||
|
||||
// updates last connection date in database
|
||||
userRec.Get("LASTCONNECTIONDATE") = GetSysTime();
|
||||
int connections = userRec.Get("TOTALCONNECTIONS");
|
||||
userRec.Get("TOTALCONNECTIONS") = connections + 1;
|
||||
|
||||
// updates database record
|
||||
db.Set(userRec);
|
||||
|
||||
// process MAC addresses of incoming connection
|
||||
// in case we wanna record them
|
||||
if(v.Find("MAC") >= 0)
|
||||
ProcessMACList(eMail, v.Get("MAC"));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PROTECT_DISCONNECT :
|
||||
{
|
||||
// we need email to disconnect
|
||||
if(v.Find("EMAIL") < 0)
|
||||
{
|
||||
res.Add("ERROR", PROTECT_MISSING_EMAIL);
|
||||
return res;
|
||||
}
|
||||
eMail = v.Get("EMAIL");
|
||||
|
||||
// we need the conneciton ID
|
||||
if(v.Find("CLIENTID") < 0)
|
||||
{
|
||||
res.Add("ERROR", PROTECT_MISSING_CLIENTID);
|
||||
return res;
|
||||
}
|
||||
clientID = (int)v.Get("CLIENTID");
|
||||
|
||||
// check whether client ID is in pool
|
||||
// otherwise it may be not connected or expired
|
||||
if(!IsClientConnected(clientID, eMail))
|
||||
return res;
|
||||
|
||||
// updates database connection time for user
|
||||
// warning --- there's a caveat if client side crashes without disconnecting
|
||||
// the total connection time won't be updated - it would make few sense anyways
|
||||
userRec = db.Get(eMail);
|
||||
int64 time = GetSysTime() - (Time)userRec.Get("LASTCONNECTIONDATE");
|
||||
time += (int)userRec.Get("TOTALCONNECTIONTIME");
|
||||
userRec.Get("TOTALCONNECTIONTIME") = time;
|
||||
db.Set(userRec);
|
||||
|
||||
DisconnectClient(clientID);
|
||||
break;
|
||||
}
|
||||
|
||||
case PROTECT_REFRESH :
|
||||
// we need email to refresh
|
||||
if(v.Find("EMAIL") < 0)
|
||||
{
|
||||
res.Add("ERROR", PROTECT_MISSING_EMAIL);
|
||||
return res;
|
||||
}
|
||||
eMail = v.Get("EMAIL");
|
||||
|
||||
// we need the conneciton ID
|
||||
if(v.Find("CLIENTID") < 0)
|
||||
{
|
||||
res.Add("ERROR", PROTECT_MISSING_CLIENTID);
|
||||
return res;
|
||||
}
|
||||
clientID = (int)v.Get("CLIENTID");
|
||||
|
||||
if(!IsClientConnected(clientID, eMail))
|
||||
{
|
||||
res.Add("ERROR", PROTECT_NOT_CONNECTED);
|
||||
return res;
|
||||
}
|
||||
break;
|
||||
|
||||
case PROTECT_GETLICENSEKEY:
|
||||
// we need email
|
||||
if(v.Find("EMAIL") < 0)
|
||||
{
|
||||
res.Add("ERROR", PROTECT_MISSING_EMAIL);
|
||||
return res;
|
||||
}
|
||||
eMail = v.Get("EMAIL");
|
||||
|
||||
// we need the conneciton ID
|
||||
if(v.Find("CLIENTID") < 0)
|
||||
{
|
||||
res.Add("ERROR", PROTECT_MISSING_CLIENTID);
|
||||
return res;
|
||||
}
|
||||
|
||||
// we shall be connected
|
||||
clientID = (int)v.Get("CLIENTID");
|
||||
if(!IsClientConnected(clientID, eMail))
|
||||
{
|
||||
res.Add("ERROR", PROTECT_NOT_CONNECTED);
|
||||
return res;
|
||||
}
|
||||
// all ok, return the key
|
||||
res.Add("KEY", appKey);
|
||||
break;
|
||||
|
||||
case PROTECT_GETLICENSEINFO :
|
||||
|
||||
// we need email
|
||||
if(v.Find("EMAIL") < 0)
|
||||
{
|
||||
res.Add("ERROR", PROTECT_MISSING_EMAIL);
|
||||
return res;
|
||||
}
|
||||
eMail = v.Get("EMAIL");
|
||||
|
||||
// we need the conneciton ID
|
||||
if(v.Find("CLIENTID") < 0)
|
||||
{
|
||||
res.Add("ERROR", PROTECT_MISSING_CLIENTID);
|
||||
return res;
|
||||
}
|
||||
// we shall be connected
|
||||
clientID = (int)v.Get("CLIENTID");
|
||||
if(!IsClientConnected(clientID, eMail))
|
||||
{
|
||||
res.Add("ERROR", PROTECT_NOT_CONNECTED);
|
||||
return res;
|
||||
}
|
||||
// get user data from database
|
||||
res = db.Get(eMail);
|
||||
// remove unnecessary data
|
||||
res.RemoveKey("ACTIVATIONKEY");
|
||||
break;
|
||||
|
||||
case PROTECT_UPDATEUSERDATA :
|
||||
{
|
||||
// we need email
|
||||
if(v.Find("EMAIL") < 0)
|
||||
{
|
||||
res.Add("ERROR", PROTECT_MISSING_EMAIL);
|
||||
return res;
|
||||
}
|
||||
eMail = v.Get("EMAIL");
|
||||
|
||||
// we need the conneciton ID
|
||||
if(v.Find("CLIENTID") < 0)
|
||||
{
|
||||
res.Add("ERROR", PROTECT_MISSING_CLIENTID);
|
||||
return res;
|
||||
}
|
||||
|
||||
// we shall be connected
|
||||
clientID = (int)v.Get("CLIENTID");
|
||||
if(!IsClientConnected(clientID, eMail))
|
||||
{
|
||||
res.Add("ERROR", PROTECT_NOT_CONNECTED);
|
||||
return res;
|
||||
}
|
||||
// get user data from database
|
||||
userRec = db.Get(eMail);
|
||||
|
||||
// avoid hacking of source packet stripping
|
||||
// data non-updateable by user
|
||||
VectorMap<String, Value>vs(v, 1);
|
||||
vs.RemoveKey("LICENSES");
|
||||
vs.RemoveKey("EXPIRATION");
|
||||
vs.RemoveKey("ACTIVATIONKEY");
|
||||
vs.RemoveKey("EMAIL");
|
||||
|
||||
// update user record
|
||||
for(int i = 0; i < vs.GetCount(); i++)
|
||||
{
|
||||
int j = userRec.Find(vs.GetKey(i));
|
||||
if(j >= 0)
|
||||
userRec[j] = vs[i];
|
||||
}
|
||||
db.Set(userRec);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// disconnect me anyways
|
||||
if(v.Find("CLIENTID") >= 0)
|
||||
{
|
||||
clientID = (int)v.Get("CLIENTID");
|
||||
DisconnectClient(clientID);
|
||||
}
|
||||
res.Add("ERROR", PROTECT_UNKNOWN_REASON);
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// sends activation mail to user
|
||||
bool ProtectServer::SendActivationMail(VectorMap<String, Value> const &userData, String const &locale)
|
||||
{
|
||||
int lang = LNGFromText(locale);
|
||||
String body = GetLngString(lang, welcomeBody);
|
||||
String subject = GetLngString(lang, welcomeSubject);
|
||||
String key = userData.Get("ACTIVATIONKEY");
|
||||
|
||||
// if no activation key field inside body, add it at end
|
||||
// trying to guess if it's HTML or simple text...
|
||||
int i;
|
||||
if( (i = body.Find("%ACTIVATIONKEY%")) < 0)
|
||||
{
|
||||
if(body.Find("HTML") >= 0)
|
||||
body << "&&&" << t_("ACTIVATION KEY : ") << key;
|
||||
else
|
||||
body << "\n\n\n" << t_("ACTIVATION KEY : ") << key;
|
||||
}
|
||||
else
|
||||
body.Replace(String("%ACTIVATIONKEY%"), key);
|
||||
|
||||
String user = userData.Get("NAME");
|
||||
if(user == "")
|
||||
user = userData.Get("EMAIL");
|
||||
body.Replace(String("%USER%"), user);
|
||||
subject.Replace(String("%USER%"), user);
|
||||
|
||||
String mime;
|
||||
if(body.Find("<HTML>") >= 0 || body.Find("<html>") >= 0)
|
||||
mime = "text/html; charset=utf-8";
|
||||
else
|
||||
mime = "text/plain; charset=utf-8";
|
||||
|
||||
smtp.New();
|
||||
smtp.TimeSent(GetSysTime());
|
||||
smtp.To(userData.Get("EMAIL"));
|
||||
smtp.Subject(subject);
|
||||
// smtp.From(serverVars.Get("SERVER_NAME"));
|
||||
smtp.Text(body, mime);
|
||||
return smtp.Send();
|
||||
}
|
||||
|
||||
// sets client ids timeout value
|
||||
ProtectServer &ProtectServer::SetIDCleanupTime(int t)
|
||||
{
|
||||
idCleanupTime = t;
|
||||
lastIDCleanupTime = GetSysTime();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// sets database cleanup time
|
||||
// used to clean up registrations with no activation on database
|
||||
ProtectServer &ProtectServer::SetDBCleanupTime(int t)
|
||||
{
|
||||
dbCleanupTime = t;
|
||||
lastDBCleanupTime = GetSysTime();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// MAC handling
|
||||
ProtectServer &ProtectServer::SetRecordMACs(bool rec)
|
||||
{
|
||||
recordMACs = rec;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ProtectServer &ProtectServer::SetCheckExistingMAC(double check)
|
||||
{
|
||||
checkExistingMAC = check;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ProtectServer &ProtectServer::SetMACAlertEMail(String const &m)
|
||||
{
|
||||
alertMACEMail = m;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ProtectServer &ProtectServer::ClearMACAlertEMail(void)
|
||||
{
|
||||
alertMACEMail = "";
|
||||
return *this;
|
||||
}
|
||||
|
||||
ProtectServer &ProtectServer::SetEnforceMAC(bool e)
|
||||
{
|
||||
enforceMAC = e;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// runs the server
|
||||
void ProtectServer::Run(void)
|
||||
{
|
||||
// try to connect to db
|
||||
if(!db.Connect())
|
||||
{
|
||||
Cout() << "Error connecting to database\n";
|
||||
return;
|
||||
}
|
||||
|
||||
// runs the SCGI server
|
||||
ScgiServer::Run();
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
171
bazaar/ProtectServer/ProtectServer.h
Normal file
171
bazaar/ProtectServer/ProtectServer.h
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
#ifndef _ProtectServer_h_
|
||||
#define _ProtectServer_h_
|
||||
|
||||
#include <Core/Core.h>
|
||||
#include <Web/Web.h>
|
||||
#include <Cypher/Cypher.h>
|
||||
|
||||
#include <ProtectClient/ProtectStatus.h>
|
||||
#include "ProtectDB.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
class ProtectServer : public ScgiServer
|
||||
{
|
||||
private:
|
||||
|
||||
struct TimeMail : Moveable<TimeMail>
|
||||
{
|
||||
Time time;
|
||||
String eMail;
|
||||
bool connected;
|
||||
TimeMail(Time const &t, String const &m, bool conn) : time(t), eMail(m) { connected = conn; }
|
||||
TimeMail() { connected = false; }
|
||||
};
|
||||
|
||||
// database for user auth
|
||||
ProtectDB db;
|
||||
|
||||
// mailer for activation mails
|
||||
SmtpMail smtp;
|
||||
|
||||
// last ID cleanup time
|
||||
Time lastIDCleanupTime;
|
||||
|
||||
// last database cleanup time
|
||||
Time lastDBCleanupTime;
|
||||
|
||||
// clients id timeout value -- defaults to 5 minutes (300 seconds)
|
||||
int idCleanupTime;
|
||||
|
||||
// database cleanup time -- default to 30 days (2592000 seconds)
|
||||
// used to clean up registrations with no activation on database
|
||||
int dbCleanupTime;
|
||||
|
||||
// list of all connected clients with their expiration dates and emails
|
||||
VectorMap<dword, TimeMail> clientLinks;
|
||||
|
||||
// number of succesful connections per registered email
|
||||
VectorMap<String, int> registeredConnections;
|
||||
|
||||
// encryption engine
|
||||
One<Cypher> cypher;
|
||||
|
||||
// key used to en/decrypt http data
|
||||
String communicationKey;
|
||||
|
||||
// welcome message sent on key activation e-mail
|
||||
// a %ACTIVATIONKEY% string inside body will be
|
||||
// replaced by current activation key
|
||||
String welcomeSubject;
|
||||
String welcomeBody;
|
||||
|
||||
void OnAccepted();
|
||||
void OnRequest();
|
||||
void OnClosed();
|
||||
|
||||
// generates an unique activation key composed by 20 random uppercase chars
|
||||
String GenerateActivationKey(void);
|
||||
|
||||
// executes database cleanup
|
||||
void DBCleanup(void);
|
||||
|
||||
// polls clients and remove those which connection has expired
|
||||
void CheckExpiredClients(void);
|
||||
|
||||
// checks client list to see if a client is connected
|
||||
// as a side effect, refresh its connection time
|
||||
bool IsClientConnected(dword clientID, String const &eMail);
|
||||
|
||||
// connects a client -- return an ID
|
||||
dword ConnectClient(String const &eMail, dword id);
|
||||
|
||||
// disconnects a client or refresh its expiration time
|
||||
void DisconnectClient(dword clientID);
|
||||
|
||||
// process client request
|
||||
// takes a VectorMap<String, Value> on input from client
|
||||
// produces a response VectorMap<String, Value> to be returned
|
||||
virtual VectorMap<String, Value> ProcessRequest(int reason, VectorMap<String, Value> const &v);
|
||||
|
||||
// Application key to be returned on auth success
|
||||
String appKey;
|
||||
|
||||
// sends activation mail to user
|
||||
bool SendActivationMail(VectorMap<String, Value> const &userData, String const &locale);
|
||||
|
||||
// MAC recording enabling
|
||||
// records ALL user's network adapter MACs on each access
|
||||
bool recordMACs;
|
||||
|
||||
// check if user want to register for demo with an already
|
||||
// used MAC
|
||||
bool checkExistingMAC;
|
||||
|
||||
// enforce MAC data from client -- to be used in transition
|
||||
// phases when some clients still don't send MAC data
|
||||
// defaults to TRUE, set to FALSE in transition time
|
||||
bool enforceMAC;
|
||||
|
||||
// alert by email if user want to register for demo with an
|
||||
// already used MAC
|
||||
String alertMACEMail;
|
||||
bool SendMACAlert(String const &eMail, Vector<String> const &mails);
|
||||
|
||||
// process MAC list in data field
|
||||
// if 'registering' is true, returns false if MAC already there
|
||||
bool ProcessMACList(String const &mail, String const &MACList, bool registering = false);
|
||||
|
||||
public:
|
||||
|
||||
// constructor - defaults to port 8787
|
||||
ProtectServer(int port = 8787);
|
||||
|
||||
// setup encryption cypher
|
||||
// WARNING : takes ownership of it
|
||||
ProtectServer &SetCypher(Cypher *c) { cypher = c; return *this; }
|
||||
|
||||
// sets encryption key
|
||||
ProtectServer &SetCommunicationKey(String const &_key) { communicationKey = _key; return *this; }
|
||||
|
||||
// sets welcome (HTML) message
|
||||
ProtectServer &SetWelcomeSubject(String const &w) { welcomeSubject = w; return *this; }
|
||||
ProtectServer &SetWelcomeBody(String const &w) { welcomeBody = w; return *this; }
|
||||
|
||||
// gets database
|
||||
ProtectDB &GetDB(void) { return db; }
|
||||
|
||||
// gets mailer
|
||||
SmtpMail &GetSmtp(void) { return smtp; }
|
||||
|
||||
// sets application key (to be returned on auth success)
|
||||
ProtectServer &SetAppKey(String const &k) { appKey = k; return *this; }
|
||||
String GetAppKey(void) { return appKey; }
|
||||
|
||||
// sets client ids timeout value
|
||||
ProtectServer &SetIDCleanupTime(int t);
|
||||
|
||||
// sets database cleanup time
|
||||
// used to clean up registrations with no activation on database
|
||||
ProtectServer &SetDBCleanupTime(int t);
|
||||
|
||||
// MAC handling
|
||||
ProtectServer &SetRecordMACs(bool rec = true);
|
||||
ProtectServer &SetNoRecordMACs(void) { return SetRecordMACs(false); }
|
||||
|
||||
ProtectServer &SetCheckExistingMAC(double check = true);
|
||||
ProtectServer &SetNoCheckExistingMAC(void) { return SetCheckExistingMAC(false); }
|
||||
|
||||
ProtectServer &SetMACAlertEMail(String const &m);
|
||||
ProtectServer &ClearMACAlertEMail(void);
|
||||
|
||||
ProtectServer &SetEnforceMAC(bool e);
|
||||
ProtectServer &SetNoEnforceMAC(void) { return SetEnforceMAC(false); }
|
||||
|
||||
// runs the server
|
||||
void Run(void);
|
||||
};
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
||||
#endif
|
||||
19
bazaar/ProtectServer/ProtectServer.upp
Normal file
19
bazaar/ProtectServer/ProtectServer.upp
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
description "Copy protection Protect package - server side\377";
|
||||
|
||||
uses
|
||||
Core,
|
||||
Cypher,
|
||||
Web,
|
||||
ProtectClient;
|
||||
|
||||
uses(USE_SQLITE) plugin\sqlite3;
|
||||
|
||||
uses(!USE_SQLITE) MySql;
|
||||
|
||||
file
|
||||
ProtectDB.sch,
|
||||
ProtectDB.h,
|
||||
ProtectDB.cpp,
|
||||
ProtectServer.h,
|
||||
ProtectServer.cpp;
|
||||
|
||||
9
bazaar/ProtectServer/init
Normal file
9
bazaar/ProtectServer/init
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef _ProtectServer_icpp_init_stub
|
||||
#define _ProtectServer_icpp_init_stub
|
||||
#include "Core/init"
|
||||
#include "Cypher/init"
|
||||
#include "Web/init"
|
||||
#include "ProtectClient/init"
|
||||
#include "plugin\sqlite3/init"
|
||||
#include "MySql/init"
|
||||
#endif
|
||||
Loading…
Reference in a new issue