forked from soutade/libgourou
Add notify server feature
This commit is contained in:
parent
9388d82138
commit
e0bb1bd4f8
|
@ -67,10 +67,11 @@ namespace gourou
|
||||||
* @brief Fulfill ACSM file to server in order to retrieve ePub fulfillment item
|
* @brief Fulfill ACSM file to server in order to retrieve ePub fulfillment item
|
||||||
*
|
*
|
||||||
* @param ACSMFile Path of ACSMFile
|
* @param ACSMFile Path of ACSMFile
|
||||||
|
* @param notify Notify server if requested by response
|
||||||
*
|
*
|
||||||
* @return a FulfillmentItem if all is OK
|
* @return a FulfillmentItem if all is OK
|
||||||
*/
|
*/
|
||||||
FulfillmentItem* fulfill(const std::string& ACSMFile);
|
FulfillmentItem* fulfill(const std::string& ACSMFile, bool notify=true);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Once fulfilled, ePub file needs to be downloaded.
|
* @brief Once fulfilled, ePub file needs to be downloaded.
|
||||||
|
@ -102,8 +103,9 @@ namespace gourou
|
||||||
*
|
*
|
||||||
* @param loanID Loan ID received during fulfill
|
* @param loanID Loan ID received during fulfill
|
||||||
* @param operatorURL URL of operator that loans this book
|
* @param operatorURL URL of operator that loans this book
|
||||||
|
* @param notify Notify server if requested by response
|
||||||
*/
|
*/
|
||||||
void returnLoan(const std::string& loanID, const std::string& operatorURL);
|
void returnLoan(const std::string& loanID, const std::string& operatorURL, bool notify=true);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return default ADEPT directory (ie /home/<user>/.config/adept)
|
* @brief Return default ADEPT directory (ie /home/<user>/.config/adept)
|
||||||
|
@ -156,7 +158,7 @@ namespace gourou
|
||||||
* @brief Send HTTP POST request to URL with document as POSTData
|
* @brief Send HTTP POST request to URL with document as POSTData
|
||||||
*/
|
*/
|
||||||
ByteArray sendRequest(const pugi::xml_document& document, const std::string& url);
|
ByteArray sendRequest(const pugi::xml_document& document, const std::string& url);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief In place encrypt data with private device key
|
* @brief In place encrypt data with private device key
|
||||||
*/
|
*/
|
||||||
|
@ -233,6 +235,9 @@ namespace gourou
|
||||||
void buildSignInRequest(pugi::xml_document& signInRequest, const std::string& adobeID, const std::string& adobePassword, const std::string& authenticationCertificate);
|
void buildSignInRequest(pugi::xml_document& signInRequest, const std::string& adobeID, const std::string& adobePassword, const std::string& authenticationCertificate);
|
||||||
void fetchLicenseServiceCertificate(const std::string& licenseURL,
|
void fetchLicenseServiceCertificate(const std::string& licenseURL,
|
||||||
const std::string& operatorURL);
|
const std::string& operatorURL);
|
||||||
|
void buildNotifyReq(pugi::xml_document& returnReq, pugi::xml_node& body);
|
||||||
|
void notifyServer(pugi::xml_node& notifyRoot);
|
||||||
|
void notifyServer(pugi::xml_document& fulfillReply);
|
||||||
std::string encryptedKeyFirstPass(pugi::xml_document& rightsDoc, const std::string& encryptedKey, const std::string& keyType);
|
std::string encryptedKeyFirstPass(pugi::xml_document& rightsDoc, const std::string& encryptedKey, const std::string& keyType);
|
||||||
void decryptADEPTKey(pugi::xml_document& rightsDoc, unsigned char* decryptedKey, const unsigned char* encryptionKey=0, unsigned encryptionKeySize=0);
|
void decryptADEPTKey(pugi::xml_document& rightsDoc, unsigned char* decryptedKey, const unsigned char* encryptionKey=0, unsigned encryptionKeySize=0);
|
||||||
void removeEPubDRM(const std::string& filenameIn, const std::string& filenameOut, const unsigned char* encryptionKey, unsigned encryptionKeySize);
|
void removeEPubDRM(const std::string& filenameIn, const std::string& filenameOut, const unsigned char* encryptionKey, unsigned encryptionKeySize);
|
||||||
|
|
|
@ -235,12 +235,7 @@ namespace gourou
|
||||||
return ltrim(rtrim(s, t), t);
|
return ltrim(rtrim(s, t), t);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static inline pugi::xml_node getNode(const pugi::xml_node& root, const char* tagName, bool throwOnNull=true)
|
||||||
* @brief Extract text node from tag in document
|
|
||||||
* It can throw an exception if tag does not exists
|
|
||||||
* or just return an empty value
|
|
||||||
*/
|
|
||||||
static inline std::string extractTextElem(const pugi::xml_node& root, const char* tagName, bool throwOnNull=true)
|
|
||||||
{
|
{
|
||||||
pugi::xpath_node xpath_node = root.select_node(tagName);
|
pugi::xpath_node xpath_node = root.select_node(tagName);
|
||||||
|
|
||||||
|
@ -249,10 +244,23 @@ namespace gourou
|
||||||
if (throwOnNull)
|
if (throwOnNull)
|
||||||
EXCEPTION(GOUROU_TAG_NOT_FOUND, "Tag " << tagName << " not found");
|
EXCEPTION(GOUROU_TAG_NOT_FOUND, "Tag " << tagName << " not found");
|
||||||
|
|
||||||
return "";
|
return pugi::xml_node();
|
||||||
}
|
}
|
||||||
|
|
||||||
pugi::xml_node node = xpath_node.node().first_child();
|
return xpath_node.node();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Extract text node from tag in document
|
||||||
|
* It can throw an exception if tag does not exists
|
||||||
|
* or just return an empty value
|
||||||
|
*/
|
||||||
|
static inline std::string extractTextElem(const pugi::xml_node& root, const char* tagName, bool throwOnNull=true)
|
||||||
|
{
|
||||||
|
pugi::xml_node node = getNode(root, tagName, throwOnNull);
|
||||||
|
|
||||||
|
node = node.first_child();
|
||||||
|
|
||||||
if (!node)
|
if (!node)
|
||||||
{
|
{
|
||||||
|
@ -266,6 +274,30 @@ namespace gourou
|
||||||
return trim(res);
|
return trim(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set text node of a tag in document
|
||||||
|
* It can throw an exception if tag does not exists
|
||||||
|
*/
|
||||||
|
static inline void setTextElem(const pugi::xml_node& root, const char* tagName,
|
||||||
|
const std::string& value, bool throwOnNull=true)
|
||||||
|
{
|
||||||
|
pugi::xml_node node = getNode(root, tagName, throwOnNull);
|
||||||
|
|
||||||
|
if (!node)
|
||||||
|
{
|
||||||
|
if (throwOnNull)
|
||||||
|
EXCEPTION(GOUROU_TAG_NOT_FOUND, "Text element for tag " << tagName << " not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = node.first_child();
|
||||||
|
|
||||||
|
if (!node)
|
||||||
|
node.append_child(pugi::node_pcdata).set_value(value.c_str());
|
||||||
|
else
|
||||||
|
node.set_value(value.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Extract text attribute from tag in document
|
* @brief Extract text attribute from tag in document
|
||||||
* It can throw an exception if attribute does not exists
|
* It can throw an exception if attribute does not exists
|
||||||
|
@ -273,17 +305,9 @@ namespace gourou
|
||||||
*/
|
*/
|
||||||
static inline std::string extractTextAttribute(const pugi::xml_node& root, const char* tagName, const char* attributeName, bool throwOnNull=true)
|
static inline std::string extractTextAttribute(const pugi::xml_node& root, const char* tagName, const char* attributeName, bool throwOnNull=true)
|
||||||
{
|
{
|
||||||
pugi::xpath_node xpath_node = root.select_node(tagName);
|
pugi::xml_node node = getNode(root, tagName, throwOnNull);
|
||||||
|
|
||||||
if (!xpath_node)
|
pugi::xml_attribute attr = node.attribute(attributeName);
|
||||||
{
|
|
||||||
if (throwOnNull)
|
|
||||||
EXCEPTION(GOUROU_TAG_NOT_FOUND, "Tag " << tagName << " not found");
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
pugi::xml_attribute attr = xpath_node.node().attribute(attributeName);
|
|
||||||
|
|
||||||
if (!attr)
|
if (!attr)
|
||||||
{
|
{
|
||||||
|
|
|
@ -495,7 +495,7 @@ namespace gourou
|
||||||
user->updateActivationFile(activationDoc);
|
user->updateActivationFile(activationDoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
FulfillmentItem* DRMProcessor::fulfill(const std::string& ACSMFile)
|
FulfillmentItem* DRMProcessor::fulfill(const std::string& ACSMFile, bool notify)
|
||||||
{
|
{
|
||||||
if (!user->getPKCS12().length())
|
if (!user->getPKCS12().length())
|
||||||
EXCEPTION(FF_NOT_ACTIVATED, "Device not activated");
|
EXCEPTION(FF_NOT_ACTIVATED, "Device not activated");
|
||||||
|
@ -580,7 +580,12 @@ namespace gourou
|
||||||
|
|
||||||
fetchLicenseServiceCertificate(licenseURL, operatorURL);
|
fetchLicenseServiceCertificate(licenseURL, operatorURL);
|
||||||
|
|
||||||
return new FulfillmentItem(fulfillReply, user);
|
FulfillmentItem* item = new FulfillmentItem(fulfillReply, user);
|
||||||
|
|
||||||
|
if (notify)
|
||||||
|
notifyServer(fulfillReply);
|
||||||
|
|
||||||
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
DRMProcessor::ITEM_TYPE DRMProcessor::download(FulfillmentItem* item, std::string path, bool resume)
|
DRMProcessor::ITEM_TYPE DRMProcessor::download(FulfillmentItem* item, std::string path, bool resume)
|
||||||
|
@ -873,7 +878,8 @@ namespace gourou
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void DRMProcessor::returnLoan(const std::string& loanID, const std::string& operatorURL)
|
void DRMProcessor::returnLoan(const std::string& loanID, const std::string& operatorURL,
|
||||||
|
bool notify)
|
||||||
{
|
{
|
||||||
pugi::xml_document returnReq;
|
pugi::xml_document returnReq;
|
||||||
|
|
||||||
|
@ -881,9 +887,73 @@ namespace gourou
|
||||||
|
|
||||||
buildReturnReq(returnReq, loanID, operatorURL);
|
buildReturnReq(returnReq, loanID, operatorURL);
|
||||||
|
|
||||||
sendRequest(returnReq, operatorURL + "/LoanReturn");
|
ByteArray replyData = sendRequest(returnReq, operatorURL + "/LoanReturn");
|
||||||
|
|
||||||
|
pugi::xml_document fulfillReply;
|
||||||
|
|
||||||
|
fulfillReply.load_string((const char*)replyData.data());
|
||||||
|
|
||||||
|
if (notify)
|
||||||
|
notifyServer(fulfillReply);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DRMProcessor::buildNotifyReq(pugi::xml_document& returnReq, pugi::xml_node& body)
|
||||||
|
{
|
||||||
|
pugi::xml_node decl = returnReq.append_child(pugi::node_declaration);
|
||||||
|
decl.append_attribute("version") = "1.0";
|
||||||
|
|
||||||
|
pugi::xml_node root = returnReq.append_child("adept:notification");
|
||||||
|
root.append_attribute("xmlns:adept") = ADOBE_ADEPT_NS;
|
||||||
|
|
||||||
|
appendTextElem(root, "adept:user", user->getUUID());
|
||||||
|
appendTextElem(root, "adept:device", user->getDeviceUUID());
|
||||||
|
body = root.append_copy(body);
|
||||||
|
body.append_attribute("xmlns") = ADOBE_ADEPT_NS;
|
||||||
|
|
||||||
|
addNonce(root);
|
||||||
|
signNode(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DRMProcessor::notifyServer(pugi::xml_node& notifyRoot)
|
||||||
|
{
|
||||||
|
std::string notifyUrl = extractTextElem(notifyRoot, "//notifyURL", false);
|
||||||
|
pugi::xml_node notifyBody = getNode(notifyRoot, "//body", false);
|
||||||
|
|
||||||
|
if (notifyUrl == "")
|
||||||
|
{
|
||||||
|
GOUROU_LOG(INFO, "No notify URL");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!notifyBody)
|
||||||
|
{
|
||||||
|
GOUROU_LOG(INFO, "No notify body");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pugi::xml_document notifyReq;
|
||||||
|
buildNotifyReq(notifyReq, notifyBody);
|
||||||
|
|
||||||
|
sendRequest(notifyReq, notifyUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DRMProcessor::notifyServer(pugi::xml_document& fulfillReply)
|
||||||
|
{
|
||||||
|
pugi::xpath_node_set notifySet = fulfillReply.select_nodes("//notify");
|
||||||
|
|
||||||
|
if (notifySet.empty())
|
||||||
|
{
|
||||||
|
GOUROU_LOG(DEBUG, "No notify request");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (pugi::xpath_node_set::const_iterator it = notifySet.begin(); it != notifySet.end(); ++it)
|
||||||
|
{
|
||||||
|
pugi::xml_node notifyRoot = it->node();
|
||||||
|
notifyServer(notifyRoot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ByteArray DRMProcessor::encryptWithDeviceKey(const unsigned char* data, unsigned int len)
|
ByteArray DRMProcessor::encryptWithDeviceKey(const unsigned char* data, unsigned int len)
|
||||||
{
|
{
|
||||||
const unsigned char* deviceKey = device->getDeviceKey();
|
const unsigned char* deviceKey = device->getDeviceKey();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user