#include "ProtectClient.h" #include "NetworkAdapter.h" NAMESPACE_UPP ProtectClient::ProtectClient() { // generates client id clientID = -1; // defaults to Snow2 Cypher cypher = new Snow2; // initializes user configuration path // (can be reset by SetUserConfigPath() ) #ifdef PLATFORM_POSIX userConfigPath = "/home/" + Upp::GetUserName() + "/." + GetExeTitle() + "/"; #else userConfigPath = GetAppDataFolder() + "/" + GetExeTitle() + "/"; #endif // must load config before connection configLoaded = false; // setup timeout for http server // a couple of seconds should be enough ! client.Timeout(2000); } ProtectClient::~ProtectClient() { // if connected, disconnect from server Disconnect(); } // stores/retrieve config data from stream void ProtectClient::Xmlize(XmlIO xml) { xml ("EMail", userEMail) ("ClientID", clientID) ("ActivationKey", activationKey) ; } bool ProtectClient::StoreConfig(void) { RealizePath(userConfigPath); String path = AppendFileName(userConfigPath, "Protect.xml"); return StoreAsXMLFile(*this, "", path); } bool ProtectClient::LoadConfig(void) { // don't load if already done if(configLoaded) return true; String path = AppendFileName(userConfigPath, "Protect.xml"); if(FileExists(path)) configLoaded = LoadFromXMLFile(*this, path); else configLoaded = false; return configLoaded; } // sets the encrypting engine // default Cypher at startup is Snow2 // WARNING -- takes Cypher ownership void ProtectClient::SetCypher(Cypher *c) { // sets the new cypher freeing previous one cypher = c; } // get MAC of client adapter(s), each separated by comma String ProtectClient::GetMACs(void) { Vector adapters = GetNetworkAdaptersInfo(); String res = ""; for(int i = 0; i < adapters.GetCount(); i++) { NetworkAdapter const &adapter = adapters[i]; // just grab cable and wireless adapters if(adapter.type == "ETHERNET" || adapter.type == "IEEE80211") { String mac = adapter.mac; if(!mac.IsEmpty()) res += mac + ","; } } // strip trailing comma if(!res.IsEmpty()) res = res.Left(res.GetCount() - 1); return res; } // sends a VectorMap to server in encrypted form // and gets its response VectorMap ProtectClient::SendMap(VectorMap const &v) { // copy vectormap adding client id and a magic number VectorMapdataMap(v, 1); dataMap.Add("APPID", "ProtectClient"); // add current locale dataMap.Add("LOCALE", LNGAsText(GetCurrentLanguage()).Left(5)); // add client's adapter MAC addresses dataMap.Add("MAC", GetMACs()); // sets cypher key (and create a random IV) cypher->SetKey(communicationKey); String postData; postData += "IV=" + HexString(cypher->GetNonce()) + "&"; postData += "DATA="; postData += HexString((*cypher)(StoreAsXML(dataMap, "ProtectClient"))); client.Post(postData); // WARNING -- PREVIOUSLY WAS ExecuteRedirect -- check on remote server!!! String contents = client.Execute(); // if contents start with "ERROR", just fetch the error desc // and put it in result map VectorMap resMap; // if contents don't start with IV field signals it if(!contents.StartsWith("IV=")) { resMap.Add("ERROR", PROTECT_MISSING_IV); resMap.Add("ERRORMSG", ProtectMessage(PROTECT_MISSING_IV)); return resMap; } // well, we've at least the IV, so we can fetch it and DATA field and decrypt StringStream s(contents); String line = s.GetLine(); String IV = ScanHexString(line.Mid(3)); line = s.GetLine(); if(!line.StartsWith("DATA=")) { resMap.Add("ERROR", PROTECT_BAD_DATA); resMap.Add("ERRORMSG", ProtectMessage(PROTECT_BAD_DATA)); return resMap; } // decodes DATA field and read VectorMap from it cypher->SetKey(communicationKey, IV); String decoded = (*cypher)(ScanHexString(line.Mid(5))); try { LoadFromXML(resMap, decoded); } catch(...) { resMap.Clear(); resMap.Add("ERROR", PROTECT_BAD_DATA); resMap.Add("ERRORMSG", ProtectMessage(PROTECT_BAD_DATA)); } return resMap; } // create a persistent link to server bool ProtectClient::Connect(void) { lastError = 0; // disconnect first, im case we're already connected Disconnect(); // load config, if not already done so // this loads previous clientID (reused if still active) // and activationKey LoadConfig(); // send a connect packet to server VectorMapv; v.Add("REASON", PROTECT_CONNECT); v.Add("EMAIL", userEMail); v.Add("CLIENTID", (int)clientID); v.Add("ACTIVATIONKEY", activationKey); VectorMap res = SendMap(v); // check for errors if(res.Find("ERROR") >= 0) { lastError = res.Get("ERROR"); clientID = -1; return false; } int i = res.Find("CLIENTID"); if(i < 0) { clientID = -1; return false; } else { // if got a new client id (previous was missing/expired) // replaces old one and store on file // clientid is used to maintain a persistent client/server relationship // on every connection, clientID timeout is updated on server side if(clientID != (dword)(int)res[i]) { clientID = (dword)(int)res[i]; return StoreConfig(); } } return true; } // disconnect from server bool ProtectClient::Disconnect(void) { lastError = 0; // sends a disconnect packet to server VectorMapv; v.Add("REASON", PROTECT_DISCONNECT); v.Add("EMAIL", userEMail); v.Add("CLIENTID", (int)clientID); VectorMap res = SendMap(v); // stores config on server; it will try to reuse clientID // on next server connection StoreConfig(); // check for errors if(res.Find("ERROR") >= 0) { lastError = res.Get("ERROR"); return false; } return true; } // refresh server connection bool ProtectClient::Refresh(void) { lastError = 0; // sends a refresh packet to server VectorMapv; v.Add("REASON", PROTECT_REFRESH); v.Add("EMAIL", userEMail); v.Add("CLIENTID", (int)clientID); VectorMap res = SendMap(v); // check for errors if(res.Find("ERROR") >= 0) { lastError = res.Get("ERROR"); // resets clientID, it'll be re-generated // on next server connection request clientID = -1; StoreConfig(); return false; } return true; } // get license key String ProtectClient::GetLicenseKey(void) { lastError = 0; // sends a getkey packet to server VectorMapv; v.Add("REASON", PROTECT_GETLICENSEKEY); v.Add("EMAIL", userEMail); v.Add("CLIENTID", (int)clientID); VectorMap res = SendMap(v); // check for errors if(res.Find("ERROR") >= 0) { lastError = res.Get("ERROR"); return ""; } if(res.Find("KEY") < 0) { lastError = 999; return ""; } return res.Get("KEY"); } // gets license info bool ProtectClient::GetLicenseInfo(void) { lastError = 0; // sends a getinfo packet to server VectorMapv; v.Add("REASON", PROTECT_GETLICENSEINFO); v.Add("EMAIL", userEMail); v.Add("CLIENTID", (int)clientID); VectorMap res = SendMap(v); // check for errors if(res.Find("ERROR") >= 0) { lastError = res.Get("ERROR"); return false; } if(res.Find("EMAIL") >= 0) userEMail = res.Get("EMAIL"); if(res.Find("NAME") >= 0) userName = res.Get("NAME"); if(res.Find("SURNAME") >= 0) userSurname = res.Get("SURNAME"); if(res.Find("ZONE") >= 0) userZone = res.Get("ZONE"); if(res.Find("COUNTRY") >= 0) userCountry = res.Get("COUNTRY"); if(res.Find("ZIP") >= 0) userZIP = res.Get("ZIP"); if(res.Find("TOWN") >= 0) userTown = res.Get("TOWN"); if(res.Find("ADDRESS") >= 0) userAddress = res.Get("ADDRESS"); if(res.Find("PHONE") >= 0) userPhone = res.Get("PHONE"); if(res.Find("FAX") >= 0) userFax = res.Get("FAX"); if(res.Find("CELL") >= 0) userCell = res.Get("CELL"); if(res.Find("EXPIRATION") >= 0) expireTime = res.Get("EXPIRATION"); if(res.Find("NUMLICENSES") >= 0) numLicenses = res.Get("NUMLICENSES"); if(res.Find("ALLOWEDVERSION") >=0) maxAllowedVersion = res.Get("ALLOWEDVERSION"); 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("SURNAME", userSurname); v.Add("ZONE", userZone); v.Add("COUNTRY", userCountry); v.Add("ZIP", userZIP); v.Add("TOWN", userTown); v.Add("ADDRESS", userAddress); 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) { lastError = 0; // sends a register packet to server VectorMapv; v.Add("REASON", PROTECT_REGISTER); v.Add("EMAIL", userEMail); v.Add("NAME", userName); v.Add("SURNAME", userSurname); v.Add("ZONE", userZone); v.Add("COUNTRY", userCountry); v.Add("ZIP", userZIP); v.Add("TOWN", userTown); v.Add("ADDRESS", userAddress); 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; } END_UPP_NAMESPACE