/*
Copyright 2021 Grégory Soutadé
This file is part of libgourou.
libgourou is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
libgourou is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with libgourou. If not, see .
*/
#include
#include
#include
#include
namespace gourou {
User::User(DRMProcessor* processor):processor(processor) {}
User::User(DRMProcessor* processor, const std::string& activationFile):
processor(processor), activationFile(activationFile)
{
parseActivationFile();
}
void User::parseActivationFile(bool throwOnNull)
{
GOUROU_LOG(DEBUG, "Parse activation file " << activationFile);
if (!activationDoc.load_file(activationFile.c_str()))
{
if (throwOnNull)
EXCEPTION(USER_INVALID_ACTIVATION_FILE, "Invalid activation file");
return;
}
try
{
pkcs12 = gourou::extractTextElem(activationDoc, "//adept:pkcs12", throwOnNull);
uuid = gourou::extractTextElem(activationDoc, "//adept:user", throwOnNull);
deviceUUID = gourou::extractTextElem(activationDoc, "//device", throwOnNull);
deviceFingerprint = gourou::extractTextElem(activationDoc, "//fingerprint", throwOnNull);
certificate = gourou::extractTextElem(activationDoc, "//adept:certificate", throwOnNull);
authenticationCertificate = gourou::extractTextElem(activationDoc, "//adept:authenticationCertificate", throwOnNull);
privateLicenseKey = gourou::extractTextElem(activationDoc, "//adept:privateLicenseKey", throwOnNull);
username = gourou::extractTextElem(activationDoc, "//adept:username", throwOnNull);
pugi::xpath_node xpath_node = activationDoc.select_node("//adept:username");
if (xpath_node)
loginMethod = xpath_node.node().attribute("method").value();
else
{
if (throwOnNull)
EXCEPTION(USER_INVALID_ACTIVATION_FILE, "Invalid activation file");
}
}
catch(gourou::Exception& e)
{
EXCEPTION(USER_INVALID_ACTIVATION_FILE, "Invalid activation file");
}
}
std::string& User::getUUID() { return uuid; }
std::string& User::getPKCS12() { return pkcs12; }
std::string& User::getDeviceUUID() { return deviceUUID; }
std::string& User::getDeviceFingerprint() { return deviceFingerprint; }
std::string& User::getUsername() { return username; }
std::string& User::getLoginMethod() { return loginMethod; }
std::string& User::getCertificate() { return certificate; }
std::string& User::getAuthenticationCertificate() { return authenticationCertificate; }
std::string& User::getPrivateLicenseKey() { return privateLicenseKey; }
void User::readActivation(pugi::xml_document& doc)
{
if (!doc.load_file(activationFile.c_str()))
EXCEPTION(USER_INVALID_ACTIVATION_FILE, "Invalid activation file");
}
void User::updateActivationFile(const char* data)
{
GOUROU_LOG(INFO, "Update Activation file : " << std::endl << data);
writeFile(activationFile, (unsigned char*)data, strlen(data));
parseActivationFile(false);
}
void User::updateActivationFile(const pugi::xml_document& doc)
{
StringXMLWriter xmlWriter;
doc.save(xmlWriter, " ");
updateActivationFile(xmlWriter.getResult().c_str());
}
std::string User::getProperty(const std::string property)
{
pugi::xpath_node xpathRes = activationDoc.select_node(property.c_str());
if (!xpathRes)
EXCEPTION(USER_NO_PROPERTY, "Property " << property << " not found in activation.xml");
std::string res = xpathRes.node().first_child().value();
return trim(res);
}
User* User::createUser(DRMProcessor* processor, const std::string& dirName, const std::string& ACSServer)
{
struct stat _stat;
if (stat(dirName.c_str(), &_stat) != 0)
{
if (mkdir_p(dirName.c_str(), S_IRWXU))
EXCEPTION(USER_MKPATH, "Unable to create " << dirName)
}
User* user = new User(processor);
bool doUpdate = false;
user->activationFile = dirName + "/activation.xml";
user->parseActivationFile(false);
pugi::xpath_node nodeActivationInfo = user->activationDoc.select_node("activation_info");
pugi::xpath_node nodeActivationServiceInfo = nodeActivationInfo.node().select_node("adept:activationServiceInfo");
pugi::xml_node activationInfo;
pugi::xml_node activationServiceInfo;
if (nodeActivationInfo && nodeActivationServiceInfo)
{
GOUROU_LOG(DEBUG, "Read previous activation configuration");
activationInfo = nodeActivationInfo.node();
activationServiceInfo = nodeActivationServiceInfo.node();
}
else
{
GOUROU_LOG(DEBUG, "Create new activation");
user->activationDoc.reset();
pugi::xml_node decl = user->activationDoc.append_child(pugi::node_declaration);
decl.append_attribute("version") = "1.0";
activationInfo = user->activationDoc.append_child("activationInfo");
activationInfo.append_attribute("xmlns") = ADOBE_ADEPT_NS;
activationServiceInfo = activationInfo.append_child("adept:activationServiceInfo");
activationServiceInfo.append_attribute("xmlns:adept") = ADOBE_ADEPT_NS;
// Go to activation Service Info
std::string activationURL = ACSServer + "/ActivationServiceInfo";
ByteArray activationServiceInfoReply = processor->sendRequest(activationURL);
pugi::xml_document docActivationServiceInfo;
docActivationServiceInfo.load_buffer(activationServiceInfoReply.data(),
activationServiceInfoReply.length());
pugi::xpath_node path = docActivationServiceInfo.select_node("//authURL");
appendTextElem(activationServiceInfo, "adept:authURL", path.node().first_child().value());
path = docActivationServiceInfo.select_node("//userInfoURL");
appendTextElem(activationServiceInfo, "adept:userInfoURL", path.node().first_child().value());
appendTextElem(activationServiceInfo, "adept:activationURL", ACSServer);
path = docActivationServiceInfo.select_node("//certificate");
appendTextElem(activationServiceInfo, "adept:certificate", path.node().first_child().value());
doUpdate = true;
}
pugi::xpath_node nodeAuthenticationCertificate = activationServiceInfo.select_node("adept:authenticationCertificate");
if (!nodeAuthenticationCertificate)
{
GOUROU_LOG(DEBUG, "Create new activation, authentication part");
pugi::xpath_node xpathRes = activationServiceInfo.select_node("adept:authURL");
if (!xpathRes)
EXCEPTION(USER_NO_AUTHENTICATION_URL, "No authentication URL");
std::string authenticationURL = xpathRes.node().first_child().value();
authenticationURL = trim(authenticationURL) + "/AuthenticationServiceInfo";
// Go to authentication Service Info
ByteArray authenticationServiceInfo = processor->sendRequest(authenticationURL);
pugi::xml_document docAuthenticationServiceInfo;
docAuthenticationServiceInfo.load_buffer(authenticationServiceInfo.data(), authenticationServiceInfo.length());
pugi::xpath_node path = docAuthenticationServiceInfo.select_node("//certificate");
appendTextElem(activationServiceInfo, "adept:authenticationCertificate", path.node().first_child().value());
doUpdate = true;
}
if (doUpdate)
user->updateActivationFile(user->activationDoc);
return user;
}
}