/* 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 . */ #ifndef _LIBGOUROU_H_ #define _LIBGOUROU_H_ #include "bytearray.h" #include "device.h" #include "user.h" #include "fulfillment_item.h" #include "drmprocessorclient.h" #include #include #ifndef HOBBES_DEFAULT_VERSION #define HOBBES_DEFAULT_VERSION "10.0.4" #endif #ifndef ACS_SERVER #define ACS_SERVER "http://adeactivate.adobe.com/adept" #endif #define LIBGOUROU_VERSION "0.8.6" namespace gourou { /** * @brief Main class that handle all ADEPTS functions (fulfill, download, signIn, activate) */ class DRMProcessor { public: static const std::string VERSION; enum ITEM_TYPE { EPUB=0, PDF }; /** * @brief Main constructor. To be used once all is configured (user has signedIn, device is activated) * * @param client Client processor * @param deviceFile Path of device.xml * @param activationFile Path of activation.xml * @param deviceKeyFile Path of devicesalt */ DRMProcessor(DRMProcessorClient* client, const std::string& deviceFile, const std::string& activationFile, const std::string& deviceKeyFile); ~DRMProcessor(); /** * @brief Fulfill ACSM file to server in order to retrieve ePub fulfillment item * * @param ACSMFile Path of ACSMFile * @param notify Notify server if requested by response * * @return a FulfillmentItem if all is OK */ FulfillmentItem* fulfill(const std::string& ACSMFile, bool notify=true); /** * @brief Once fulfilled, ePub file needs to be downloaded. * During this operation, DRM information is added into downloaded file * * @param item Item from fulfill() method * @param path Output file path * @param resume false if target file should be truncated, true to try resume download * * @return Type of downloaded item */ ITEM_TYPE download(FulfillmentItem* item, std::string path, bool resume=false); /** * @brief SignIn into ACS Server (required to activate device) * * @param adobeID AdobeID username * @param adobePassword Adobe password */ void signIn(const std::string& adobeID, const std::string& adobePassword); /** * @brief Activate newly created device (user must have successfuly signedIn before) */ void activateDevice(); /** * @brief Return loaned book to server * * @param loanID Loan ID received during fulfill * @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, bool notify=true); /** * @brief Return default ADEPT directory (ie /home//.config/adept) */ static std::string getDefaultAdeptDir(void); /** * @brief Create a new ADEPT environment (device.xml, devicesalt and activation.xml). * * @param client Client processor * @param randomSerial Always generate a new device (or not) * @param dirName Directory where to put generated files (.adept) * @param hobbes Override hobbes default version * @param ACSServer Override main ACS server (default adeactivate.adobe.com) */ static DRMProcessor* createDRMProcessor(DRMProcessorClient* client, bool randomSerial=false, std::string dirName=std::string(""), const std::string& hobbes=std::string(HOBBES_DEFAULT_VERSION), const std::string& ACSServer=ACS_SERVER); /** * @brief Get current log level */ static int getLogLevel(); /** * @brief Set log level (higher number for verbose output) */ static void setLogLevel(int logLevel); /** * Functions used internally, should not be called by user */ /** * @brief Send HTTP (GET or POST) request * * @param URL HTTP URL * @param POSTData POST data if needed, if not set, a GET request is done * @param contentType Optional content type of POST Data * @param responseHeaders Optional Response headers of HTTP request * @param fd Optional File descriptor to write received data * @param resume false if target file should be truncated, true to try resume download (works only in combination of a valid fd) * * @return data of HTTP response */ ByteArray sendRequest(const std::string& URL, const std::string& POSTData=std::string(), const char* contentType=0, std::map* responseHeaders=0, int fd=0, bool resume=false); /** * @brief Send HTTP POST request to URL with document as POSTData */ ByteArray sendRequest(const pugi::xml_document& document, const std::string& url); /** * @brief In place encrypt data with private device key */ ByteArray encryptWithDeviceKey(const unsigned char* data, unsigned int len); /** * @brief In place decrypt data with private device key */ ByteArray decryptWithDeviceKey(const unsigned char* data, unsigned int len); /** * @brief Return base64 encoded value of RSA public key */ std::string serializeRSAPublicKey(void* rsa); /** * @brief Return base64 encoded value of RSA private key encrypted with private device key */ std::string serializeRSAPrivateKey(void* rsa); /** * @brief Export clear private license key into path */ void exportPrivateLicenseKey(std::string path); /** * @brief Get current user */ User* getUser() { return user; } /** * @brief Get current device */ Device* getDevice() { return device; } /** * @brief Get current client */ DRMProcessorClient* getClient() { return client; } /** * @brief Remove ADEPT DRM * Warning: for PDF format, filenameIn must be different than filenameOut * * @param filenameIn Input file (with ADEPT DRM) * @param filenameOut Output file (without ADEPT DRM) * @param type Type of file (ePub or PDF) * @param encryptionKey Optional encryption key, do not try to decrypt the one inside input file * @param encryptionKeySize Size of encryption key (if provided) */ void removeDRM(const std::string& filenameIn, const std::string& filenameOut, ITEM_TYPE type, const unsigned char* encryptionKey=0, unsigned encryptionKeySize=0); private: gourou::DRMProcessorClient* client; gourou::Device* device; gourou::User* user; DRMProcessor(DRMProcessorClient* client); void pushString(void* sha_ctx, const std::string& string); void pushTag(void* sha_ctx, uint8_t tag); void hashNode(const pugi::xml_node& root, void *sha_ctx, std::map nsHash); void hashNode(const pugi::xml_node& root, unsigned char* sha_out); void signNode(pugi::xml_node& rootNode); void addNonce(pugi::xml_node& root); void buildAuthRequest(pugi::xml_document& authReq); void buildInitLicenseServiceRequest(pugi::xml_document& initLicReq, std::string operatorURL); void doOperatorAuth(std::string operatorURL); 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, 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); 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 generatePDFObjectKey(int version, const unsigned char* masterKey, unsigned int masterKeyLength, int objectId, int objectGenerationNumber, unsigned char* keyOut); void removePDFDRM(const std::string& filenameIn, const std::string& filenameOut, const unsigned char* encryptionKey, unsigned encryptionKeySize); }; } #endif