Manage loan tokens

This commit is contained in:
Grégory Soutadé 2022-04-03 09:32:06 +02:00
parent 2e7e352e35
commit 570ad83747
8 changed files with 207 additions and 8 deletions

View File

@ -36,7 +36,7 @@ TARGETDIR := bin
SRCEXT := cpp
OBJEXT := o
SOURCES = src/libgourou.cpp src/user.cpp src/device.cpp src/fulfillment_item.cpp src/bytearray.cpp src/pugixml.cpp
SOURCES = src/libgourou.cpp src/user.cpp src/device.cpp src/fulfillment_item.cpp src/loan_token.cpp src/bytearray.cpp src/pugixml.cpp
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.$(OBJEXT)))
all: lib obj $(TARGETS)

View File

@ -20,7 +20,7 @@
#ifndef _FULFILLMENT_ITEM_H_
#define _FULFILLMENT_ITEM_H_
#include "bytearray.h"
#include "loan_token.h"
#include <pugixml.hpp>
@ -42,6 +42,8 @@ namespace gourou
*/
FulfillmentItem(pugi::xml_document& doc, User* user);
~FulfillmentItem();
/**
* @brief Return metadata value from ACSM metadata section
*
@ -64,13 +66,19 @@ namespace gourou
*/
std::string getResource();
/**
* @brief Return loan token if there is one
*/
LoanToken* getLoanToken();
private:
pugi::xml_document fulfillDoc;
pugi::xml_node metadatas;
pugi::xml_document rights;
std::string downloadURL;
std::string resource;
LoanToken* loanToken;
void buildRights(const pugi::xml_node& licenseToken, User* user);
};
}

View File

@ -40,7 +40,7 @@
#define ACS_SERVER "http://adeactivate.adobe.com/adept"
#endif
#define LIBGOUROU_VERSION "0.6"
#define LIBGOUROU_VERSION "0.7"
namespace gourou
{
@ -100,6 +100,14 @@ namespace gourou
*/
void activateDevice();
/**
* @brief Return loaned book to server
*
* @param loanID Loan ID received during fulfill
* @param operatorURL URL of operator that loans this book
*/
void returnLoan(const std::string& loanID, const std::string& operatorURL);
/**
* @brief Create a new ADEPT environment (device.xml, devicesalt and activation.xml).
*
@ -218,6 +226,7 @@ namespace gourou
void operatorAuth(std::string operatorURL);
void buildFulfillRequest(pugi::xml_document& acsmDoc, pugi::xml_document& fulfillReq);
void buildActivateReq(pugi::xml_document& activateReq);
void buildReturnReq(pugi::xml_document& returnReq, const std::string& loanID, const std::string& operatorURL);
ByteArray sendFulfillRequest(const pugi::xml_document& document, const std::string& url);
void buildSignInRequest(pugi::xml_document& signInRequest, const std::string& adobeID, const std::string& adobePassword, const std::string& authenticationCertificate);
void fetchLicenseServiceCertificate(const std::string& licenseURL,

View File

@ -55,7 +55,8 @@ namespace gourou
GOUROU_INVALID_CLIENT,
GOUROU_TAG_NOT_FOUND,
GOUROU_ADEPT_ERROR,
GOUROU_FILE_ERROR
GOUROU_FILE_ERROR,
GOUROU_INVALID_PROPERTY
};
enum FULFILL_ERROR {
@ -96,7 +97,8 @@ namespace gourou
};
enum FULFILL_ITEM_ERROR {
FFI_INVALID_FULFILLMENT_DATA = 0x4000
FFI_INVALID_FULFILLMENT_DATA = 0x4000,
FFI_INVALID_LOAN_TOKEN
};
enum CLIENT_ERROR {

54
include/loan_token.h Normal file
View File

@ -0,0 +1,54 @@
/*
Copyright 2022 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 <http://www.gnu.org/licenses/>.
*/
#ifndef _LOAN_TOKEN_H_
#define _LOAN_TOKEN_H_
#include <map>
#include <pugixml.hpp>
namespace gourou
{
/**
* @brief This class is a container for a fulfillment object
*/
class LoanToken
{
public:
/**
* @brief Main constructor. Not to be called by user
*
* @param doc Fulfill reply
*/
LoanToken(pugi::xml_document& doc);
/**
* @brief Get a property (id, operatorURL, validity)
*/
std::string getProperty(const std::string& property, const std::string& _default=std::string(""));
std::string operator[](const std::string& property);
private:
std::map<std::string, std::string> properties;
};
}
#endif

View File

@ -24,7 +24,7 @@
namespace gourou
{
FulfillmentItem::FulfillmentItem(pugi::xml_document& doc, User* user)
: fulfillDoc()
: fulfillDoc(), loanToken(0)
{
fulfillDoc.reset(doc); /* We must keep a copy */
metadatas = fulfillDoc.select_node("//metadata").node();
@ -50,8 +50,25 @@ namespace gourou
EXCEPTION(FFI_INVALID_FULFILLMENT_DATA, "Any license token in document");
buildRights(licenseToken, user);
node = doc.select_node("/envelope/fulfillmentResult/returnable").node();
try
{
if (node && node.first_child().value() == std::string("true"))
loanToken = new LoanToken(doc);
}
catch(std::exception& e)
{
GOUROU_LOG(ERROR, "Book is returnable, but contains invalid loan token");
GOUROU_LOG(ERROR, e.what());
}
}
FulfillmentItem::~FulfillmentItem()
{
if (loanToken) delete loanToken;
}
void FulfillmentItem::buildRights(const pugi::xml_node& licenseToken, User* user)
{
pugi::xml_node decl = rights.append_child(pugi::node_declaration);
@ -103,4 +120,9 @@ namespace gourou
{
return resource;
}
LoanToken* FulfillmentItem::getLoanToken()
{
return loanToken;
}
}

View File

@ -837,6 +837,33 @@ namespace gourou
user->updateActivationFile(activationDoc);
}
void DRMProcessor::buildReturnReq(pugi::xml_document& returnReq, const std::string& loanID, const std::string& operatorURL)
{
pugi::xml_node decl = returnReq.append_child(pugi::node_declaration);
decl.append_attribute("version") = "1.0";
pugi::xml_node root = returnReq.append_child("adept:loanReturn");
root.append_attribute("xmlns:adept") = ADOBE_ADEPT_NS;
appendTextElem(root, "adept:user", user->getUUID());
appendTextElem(root, "adept:device", user->getDeviceUUID());
appendTextElem(root, "adept:loan", loanID);
addNonce(root);
signNode(root);
}
void DRMProcessor::returnLoan(const std::string& loanID, const std::string& operatorURL)
{
pugi::xml_document returnReq;
GOUROU_LOG(INFO, "Return loan " << loanID);
buildReturnReq(returnReq, loanID, operatorURL);
sendRequest(returnReq, operatorURL + "/LoanReturn");
}
ByteArray DRMProcessor::encryptWithDeviceKey(const unsigned char* data, unsigned int len)
{
const unsigned char* deviceKey = device->getDeviceKey();

77
src/loan_token.cpp Normal file
View File

@ -0,0 +1,77 @@
/*
Copyright 2022 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 <http://www.gnu.org/licenses/>.
*/
#include "libgourou_common.h"
#include "loan_token.h"
namespace gourou
{
LoanToken::LoanToken(pugi::xml_document& doc)
{
pugi::xml_node node = doc.select_node("/envelope/loanToken").node();
if (!node)
EXCEPTION(FFI_INVALID_LOAN_TOKEN, "No loanToken element in document");
node = doc.select_node("/envelope/loanToken/loan").node();
if (!node)
EXCEPTION(FFI_INVALID_LOAN_TOKEN, "No loanToken/loan element in document");
properties["id"] = node.first_child().value();
node = doc.select_node("/envelope/loanToken/operatorURL").node();
if (!node)
EXCEPTION(FFI_INVALID_LOAN_TOKEN, "No loanToken/operatorURL element in document");
properties["operatorURL"] = node.first_child().value();
node = doc.select_node("/envelope/fulfillmentResult/resourceItemInfo/licenseToken/permissions/display/until").node();
if (node)
properties["validity"] = node.first_child().value();
else
{
node = doc.select_node("/envelope/fulfillmentResult/resourceItemInfo/licenseToken/permissions/play/until").node();
if (node)
properties["validity"] = node.first_child().value();
else
EXCEPTION(FFI_INVALID_LOAN_TOKEN, "No loanToken/operatorURL element in document");
}
}
std::string LoanToken::getProperty(const std::string& property, const std::string& _default)
{
if (properties.find(property) == properties.end())
{
if (_default == "")
EXCEPTION(GOUROU_INVALID_PROPERTY, "Invalid property " << property);
return _default;
}
return properties[property];
}
std::string LoanToken::operator[](const std::string& property)
{
return getProperty(property);
}
}