From ae32efdfbb2987a9ee042bfd7e2b4e4a442bcd42 Mon Sep 17 00:00:00 2001 From: micio Date: Wed, 13 Oct 2010 12:15:14 +0000 Subject: [PATCH] Bazaar/Protect : more features and bugfixes git-svn-id: svn://ultimatepp.org/upp/trunk@2777 f0d560ea-af0d-0410-9eb7-867de7ffcac7 --- bazaar/Protect/Protect.upp | 4 +- bazaar/Protect/ProtectClient.cpp | 34 ++++- bazaar/Protect/ProtectClient.h | 12 ++ bazaar/Protect/ProtectServer.cpp | 225 ++++++++++++++++++++++++++----- bazaar/Protect/ProtectServer.h | 10 +- bazaar/Protect/ProtectStatus.cpp | 3 + bazaar/Protect/ProtectStatus.h | 18 ++- bazaar/Protect/init | 2 +- 8 files changed, 264 insertions(+), 44 deletions(-) diff --git a/bazaar/Protect/Protect.upp b/bazaar/Protect/Protect.upp index fe162da1a..8e9953727 100644 --- a/bazaar/Protect/Protect.upp +++ b/bazaar/Protect/Protect.upp @@ -2,9 +2,9 @@ description "Software copy protection module\377"; uses Core, - ScgiServer, Cypher, - MySql; + MySql, + Web; file ProtectStatus.h, diff --git a/bazaar/Protect/ProtectClient.cpp b/bazaar/Protect/ProtectClient.cpp index fc43ab05c..4b5ebfa68 100644 --- a/bazaar/Protect/ProtectClient.cpp +++ b/bazaar/Protect/ProtectClient.cpp @@ -91,13 +91,14 @@ bool ProtectClient::Connect(void) { lastError = 0; - // if already connected, disconnect first + // disconnect first, im case we're already connected Disconnect(); // send a connect packet to server VectorMapv; v.Add("REASON", PROTECT_CONNECT); v.Add("EMAIL", userEMail); + v.Add("CLIENTID", (int)clientID); VectorMap res = SendMap(v); // check for errors @@ -204,9 +205,8 @@ bool ProtectClient::GetLicenseInfo(void) lastError = res.Get("ERROR"); return false; } - if(res.Find("EMAIL") >= 0) userEMail = res.Get("EMAIL"); - if(res.Find("USERNAME") >= 0) userName = res.Get("NAME"); + if(res.Find("NAME") >= 0) userName = res.Get("NAME"); if(res.Find("ADDRESS") >= 0) userAddress = res.Get("ADDRESS"); if(res.Find("COUNTRY") >= 0) userCountry = res.Get("COUNTRY"); if(res.Find("ZIP") >= 0) userZIP = res.Get("ZIP"); @@ -219,6 +219,34 @@ bool ProtectClient::GetLicenseInfo(void) return true; } +// updates user data on server +bool ProtectClient::UpdateUserData(void) +{ + lastError = 0; + + // sends a register packet to server + VectorMapv; + v.Add("REASON", PROTECT_UPDATEUSERDATA); + v.Add("CLIENTID", (int)clientID); + v.Add("EMAIL", userEMail); + v.Add("NAME", userName); + v.Add("ADDRESS", userAddress); + v.Add("COUNTRY", userCountry); + v.Add("ZIP", userZIP); + v.Add("PHONE", userPhone); + v.Add("FAX", userFax); + v.Add("CELL", userCell); + VectorMap res = SendMap(v); + + // check for errors + if(res.Find("ERROR") >= 0) + { + lastError = res.Get("ERROR"); + return false; + } + return true; +} + // register app bool ProtectClient::Register(void) { diff --git a/bazaar/Protect/ProtectClient.h b/bazaar/Protect/ProtectClient.h index c0207717f..df2741ba5 100644 --- a/bazaar/Protect/ProtectClient.h +++ b/bazaar/Protect/ProtectClient.h @@ -87,6 +87,9 @@ class ProtectClient // gets license info bool GetLicenseInfo(void); + // updates user data on server + bool UpdateUserData(void); + // register app bool Register(void); @@ -100,6 +103,15 @@ class ProtectClient ProtectClient &SetUserPhone(String const &phone) { userPhone = phone; return *this; } ProtectClient &SetUserFax(String const &fax) { userFax = fax; return *this; } ProtectClient &SetUserCell(String const &cell) { userCell = cell; return *this; } + + String GetUserEMail(void) { return userEMail; } + String GetUserName(void) { return userName; } + String GetUserAddress(void) { return userAddress; } + String GetUserCountry(void) { return userCountry; } + String GetUserZip(void) { return userZIP; } + String GetUserPhone(void) { return userPhone; } + String GetUserFax(void) { return userFax; } + String GetUserCell(void) { return userCell; } }; END_UPP_NAMESPACE diff --git a/bazaar/Protect/ProtectServer.cpp b/bazaar/Protect/ProtectServer.cpp index ce4ec298c..28b25693c 100644 --- a/bazaar/Protect/ProtectServer.cpp +++ b/bazaar/Protect/ProtectServer.cpp @@ -109,7 +109,7 @@ dword ProtectServer::ConnectClient(String const &eMail) { id = Random(); } - while(clientLinks.Find(id) >= 0); + while(id == 0 || id == -1 || clientLinks.Find(id) >= 0); // adds to clientLinks and to registered emails count clientLinks.Add(id, TimeMail(GetSysTime() + clientTimeout, eMail)); @@ -151,34 +151,50 @@ void ProtectServer::OnRequest() int err = 0; VectorMap data; VectorMap results; + String IV; - clientSock.Write("Content-Type: text/plain\r\n\r\n"); - - // ignore requests without post data - if(!HasPostData()) - err = PROTECT_BAD_REQUEST; - // post data should contain at least an IV field and a DATA field - else if(post.Find("IV") < 0 || post.Find("DATA") < 0) - err = PROTECT_MISSING_IV; - else + // POST rwquest ? + if(HasPostData()) { - // gets IV and setup the cypher to decrypt DATA field - String IV = ScanHexString(post.GetString("IV")); - cypher->SetKey(key, IV); - - // decrypts DATA field and build its vectormap - String decoded; - try + // all requests besides PROTECT_ACTIVATE go through post + if(post.Find("IV") < 0) + err = PROTECT_MISSING_IV; + else { - decoded = (*cypher)(ScanHexString(post.GetString("DATA"))); - LoadFromXML(data, decoded); - } - catch(...) - { - err = PROTECT_BAD_DATA; + IV = ScanHexString(post.GetString("IV")); + if(post.Find("DATA") < 0) + err = PROTECT_MISSING_DATA; + else + { + cypher->SetKey(key, IV); + String decoded = (*cypher)(ScanHexString(post.GetString("DATA"))); + LoadFromXML(data, decoded); + } } } - + // GET rwquest ? + else if(query.GetCount()) + { + // here should come just PROTECT_ACTIVATE requests + if(query.Find("IV") < 0) + err = PROTECT_MISSING_IV; + else + { + IV = ScanHexString(query.GetString("IV")); + if(query.Find("DATA") < 0) + err = PROTECT_MISSING_DATA; + else + { + cypher->SetKey(key, IV); + String decoded = (*cypher)(ScanHexString(query.GetString("DATA"))); + LoadFromXML(data, decoded); + } + } + } + else + err = PROTECT_BAD_REQUEST; + + // Get request reason and process it // supports following reasons : // CONNECT establish connection to server @@ -201,11 +217,28 @@ void ProtectServer::OnRequest() else if(results.Find("ERROR") >= 0) results.Add("ERRORMSG", ProtectMessage(results.Get("ERROR"))); - // encodes results and send back to client - cypher->SetKey(key); - clientSock.Write("IV=" + HexString(cypher->GetNonce()) + "\r\n"); - String encoded = HexString((*cypher)(StoreAsXML(results, "ProtectServer"))); - clientSock.Write("DATA=" + encoded + "\r\n"); + // if not ACTIVATION REQUEST encodes results and send back to client + if(data.Get("REASON") != PROTECT_ACTIVATE) + { + clientSock.Write("Content-Type: text/plain\r\n\r\n"); + cypher->SetKey(key); + clientSock.Write("IV=" + HexString(cypher->GetNonce()) + "\r\n"); + String encoded = HexString((*cypher)(StoreAsXML(results, "ProtectServer"))); + clientSock.Write("DATA=" + encoded + "\r\n"); + } + // otherwise send a fancy welcome html -- replacing %NAME% with user name + else + { + String w; + clientSock.Write("Content-Type: text/html\r\n\r\n"); + if(results.Find("ERROR") >= 0) + w = welcome; + else + w = activationFailed; + data = db.Get(data.Get("EMAIL")); + w.Replace("%USER%", data.Get("NAME")); + clientSock.Write(w); + } } void ProtectServer::OnClosed() @@ -222,6 +255,7 @@ VectorMap ProtectServer::ProcessRequest(int reason, VectorMap userRec; String eMail; + String activationKey; int numConnections; switch(reason) @@ -258,6 +292,7 @@ VectorMap ProtectServer::ProcessRequest(int reason, VectorMap ProtectServer::ProcessRequest(int reason, VectorMap ProtectServer::ProcessRequest(int reason, VectorMap ProtectServer::ProcessRequest(int reason, VectorMapvs(v, 1); + vs.RemoveKey("LICENSES"); + vs.RemoveKey("EXPIRATION"); + vs.RemoveKey("ACTIVATIONKEY"); + vs.RemoveKey("ACTIVATIONSENT"); + vs.RemoveKey("ACTIVATED"); + 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; } @@ -377,9 +526,25 @@ VectorMap ProtectServer::ProcessRequest(int reason, VectorMap const &userData) { + // build request map + VectorMapreq; + req.Add("REASON", PROTECT_ACTIVATE); + req.Add("EMAIL", userData.Get("EMAIL")); + req.Add("ACTIVATIONKEY", userData.Get("ACTIVATIONKEY")); + + // builds activation link + String link = "http://" + serverVars.Get("SERVER_NAME") + serverVars.Get("REQUEST_URI") + "?"; + + // encodes results and send back to client + cypher->SetKey(key); + link += "IV=" + HexString(cypher->GetNonce()) + "&"; + String encoded = HexString((*cypher)(StoreAsXML(req, "ProtectServer"))); + link += "DATA=" + encoded; + smtp.To(userData.Get("EMAIL")); smtp.Subject("APPLICATION ACTIVATION"); - smtp.Text("http://www.timberstruct.it?DATA=" + (String)userData.Get("ACTIVATIONKEY")); + smtp.From(serverVars.Get("SERVER_NAME")); + smtp.Text(link); return smtp.Send(); } diff --git a/bazaar/Protect/ProtectServer.h b/bazaar/Protect/ProtectServer.h index f4d4a428f..2b18fab3f 100644 --- a/bazaar/Protect/ProtectServer.h +++ b/bazaar/Protect/ProtectServer.h @@ -2,7 +2,7 @@ #define _ProtectServer_h_ #include -#include +#include #include #include "ProtectStatus.h" @@ -42,6 +42,10 @@ class ProtectServer : public ScgiServer // key used to en/decrypt http data String key; + + // welcome and activation failed messages sent on key activation + String welcome; + String activationFailed; void OnAccepted(); void OnRequest(); @@ -83,6 +87,10 @@ public: // sets encryption key ProtectServer &SetKey(String const &_key) { key = _key; return *this; } + // sets welcome and activation failed (HTML) messages + ProtectServer &SetWelcome(String const &w) { welcome = w; return *this; } + ProtectServer &SetActivationFailed(String const &a) { activationFailed = a; return *this; } + // gets database ProtectDB &GetDB(void) { return db; } diff --git a/bazaar/Protect/ProtectStatus.cpp b/bazaar/Protect/ProtectStatus.cpp index 36258d46d..cad533d09 100644 --- a/bazaar/Protect/ProtectStatus.cpp +++ b/bazaar/Protect/ProtectStatus.cpp @@ -9,11 +9,13 @@ const char *__ProtectMessages[] = tt_("HTTP SERVER ERROR"), tt_("BAD REQUEST"), tt_("MISSING INITIALIZATION VECTOR ON DATA"), + tt_("MISSING DATA FIELD"), tt_("MISSING EMAIL ON DATA"), tt_("ILL-FORMED EMAIL ADDRESS"), tt_("MISSING CONNECTION REASON ON DATA"), tt_("UNKNOWN CONNECTION REASON"), tt_("MISSING CLIENT ID ON DATA"), + tt_("MISSING ACTIVATION KEY ON DATA"), tt_("BAD REQUEST DATA"), tt_("NOT CONNECTED TO SERVER"), tt_("SERVER CONNECTION EXPIRED"), @@ -43,6 +45,7 @@ const char *__ProtectReasons[] = "REFRESH", // refreshes server connection (to restart timeout) "GETKEY", // gets application key "REGISTER", // registers app for timed demo + "ACTIVATE", // activate registration by click on email link "GETLICENSEINFO" // gets info about license (name, expiration date, app version....) }; diff --git a/bazaar/Protect/ProtectStatus.h b/bazaar/Protect/ProtectStatus.h index a3c788946..8a5f69ce4 100644 --- a/bazaar/Protect/ProtectStatus.h +++ b/bazaar/Protect/ProtectStatus.h @@ -11,11 +11,13 @@ typedef enum { PROTECT_HTTP_ERROR, // error on HTTP communication with server PROTECT_BAD_REQUEST, // missing POST data on request PROTECT_MISSING_IV, // missing Initialization Vector on POST data + PROTECT_MISSING_DATA, // missing DATA field on POST data PROTECT_MISSING_EMAIL, // missing mandatory EMAIL field in POST DATA PROTECT_INVALID_EMAIL, // ill-formed email address PROTECT_MISSING_REASON, // missing connection's reason PROTECT_UNKNOWN_REASON, // unknown connection's reason PROTECT_MISSING_CLIENTID, // missing client connection ID in POST DATA + PROTECT_MISSING_ACTIVATIONKEY, // missing activation key on activation request PROTECT_BAD_DATA, // missing mandatory fields in POST DATA PROTECT_NOT_CONNECTED, // not connected to server -- must connect first PROTECT_CONNECTION_EXPIRED, // server connection timeout -- should refresh more often @@ -33,13 +35,15 @@ extern String ProtectMessage(int m); // server request reasons typedef enum { - PROTECT_BAD_REASON, // internal error - PROTECT_CONNECT, // establish connection to server - PROTECT_DISCONNECT, // frees server connection - PROTECT_REFRESH, // refreshes server connection (to restart timeout) - PROTECT_GETKEY, // gets application key - PROTECT_REGISTER, // registers app for timed demo - PROTECT_GETLICENSEINFO // gets info about license (name, expiration date, app version....) + PROTECT_BAD_REASON, // internal error + PROTECT_CONNECT, // establish connection to server + PROTECT_DISCONNECT, // frees server connection + PROTECT_REFRESH, // refreshes server connection (to restart timeout) + PROTECT_GETKEY, // gets application key + PROTECT_REGISTER, // registers app for timed demo + PROTECT_ACTIVATE, // activate registration by click on email link + PROTECT_GETLICENSEINFO, // gets info about license (name, expiration date, app version....) + PROTECT_UPDATEUSERDATA // update user-modifiable user data (name, address....) } ProtectReasons; // get reason in string format diff --git a/bazaar/Protect/init b/bazaar/Protect/init index a110a890d..790e663f9 100644 --- a/bazaar/Protect/init +++ b/bazaar/Protect/init @@ -1,7 +1,7 @@ #ifndef _Protect_icpp_init_stub #define _Protect_icpp_init_stub #include "Core/init" -#include "ScgiServer/init" #include "Cypher/init" #include "MySql/init" +#include "Web/init" #endif