Initial commit
This commit is contained in:
commit
d5ce4d625e
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
obj
|
||||
lib
|
||||
*.a
|
||||
*.so
|
||||
*~
|
||||
utils/acsmdownloader
|
||||
utils/activate
|
||||
.adept
|
165
LICENSE
Normal file
165
LICENSE
Normal file
|
@ -0,0 +1,165 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
55
Makefile
Normal file
55
Makefile
Normal file
|
@ -0,0 +1,55 @@
|
|||
|
||||
AR ?= $(CROSS)ar
|
||||
CXX ?= $(CROSS)g++
|
||||
|
||||
CXXFLAGS=-Wall -fPIC -I./include -I./lib -I./lib/pugixml/src/
|
||||
LDFLAGS=
|
||||
|
||||
ifneq ($(DEBUG),)
|
||||
CXXFLAGS += -ggdb -O0
|
||||
else
|
||||
CXXFLAGS += -O2
|
||||
endif
|
||||
|
||||
SRCDIR := src
|
||||
INCDIR := inc
|
||||
BUILDDIR := obj
|
||||
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
|
||||
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.$(OBJEXT)))
|
||||
|
||||
.PHONY: utils
|
||||
|
||||
all: lib obj libgourou utils
|
||||
|
||||
lib:
|
||||
mkdir lib
|
||||
./scripts/setup.sh
|
||||
|
||||
obj:
|
||||
mkdir obj
|
||||
|
||||
$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT)
|
||||
$(CXX) $(CXXFLAGS) -c $^ -o $@
|
||||
|
||||
libgourou: libgourou.a libgourou.so
|
||||
|
||||
libgourou.a: $(OBJECTS)
|
||||
$(AR) crs $@ obj/*.o
|
||||
|
||||
libgourou.so: libgourou.a
|
||||
$(CXX) obj/*.o $(LDFLAGS) -o $@ -shared
|
||||
|
||||
utils:
|
||||
make -C utils ROOT=$(PWD) CXX=$(CXX) AR=$(AR) DEBUG=$(DEBUG)
|
||||
|
||||
clean:
|
||||
rm -rf libgourou.a libgourou.so obj
|
||||
make -C utils clean
|
||||
|
||||
ultraclean: clean
|
||||
rm -rf lib
|
||||
make -C utils ultraclean
|
85
README.md
Normal file
85
README.md
Normal file
|
@ -0,0 +1,85 @@
|
|||
Introduction
|
||||
------------
|
||||
|
||||
libgourou is a free implementation of Adobe's ADEPT protocol used to add DRM on ePub files. It overcome the lacks of Adobe support for Linux platforms.
|
||||
|
||||
|
||||
Architecture
|
||||
------------
|
||||
|
||||
Like RMSDK, libgourou has a client/server scheme. All platform specific functions (crypto, network...) has to be implemented in a client class (that derives from DRMProcessorClient) while server implements ADEPT protocol.
|
||||
A reference implementation using Qt, OpenSSL and libzip is provided (in _utils_ directory).
|
||||
|
||||
Main fucntions to use from gourou::DRMProcessor are :
|
||||
|
||||
* Get an ePub from an ACSM file : _fulfill()_ and _download()_
|
||||
* Create a new device : _createDRMProcessor()_
|
||||
* Register a new device : _signIn()_ and _activateDevice()_
|
||||
|
||||
|
||||
You can import configuration from (at least) :
|
||||
|
||||
* Kobo device : .adept/device.xml, .adept/devicesalt and .adept/activation.xml
|
||||
* Bookeen device : .adobe-digital-editions/device.xml, root/devkey.bin and .adobe-digital-editions/activation.xml
|
||||
|
||||
Or create a new one. Be careful : there is a limited number of devices that can be created bye one account.
|
||||
|
||||
ePub are encrypted using a shared key : one account / multiple devices, so you can create and register a device into your computer and read downloaded (and encrypted) ePub file with your eReader configured using the same AdobeID account.
|
||||
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
For libgourou :
|
||||
|
||||
* None
|
||||
|
||||
For utils :
|
||||
|
||||
* QT5Core
|
||||
* QT5Network
|
||||
* OpenSSL
|
||||
* libzip
|
||||
|
||||
|
||||
Compilation
|
||||
-----------
|
||||
|
||||
User _make_
|
||||
|
||||
_make_ [CROSS=XXX] [DEBUG=1]
|
||||
|
||||
CROSS can define a cross compiler prefix (ie arm-linux-gnueabihf-)
|
||||
|
||||
DEBUG can be set to compile in DEBUG mode
|
||||
|
||||
|
||||
Utils
|
||||
-----
|
||||
|
||||
You can import configuration from your eReader or create a new one with utils/activate :
|
||||
|
||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD
|
||||
./utils/activate -u <USERNAME>
|
||||
|
||||
Then a _./.adept_ directory is created with all configuration file
|
||||
|
||||
To download an ePub :
|
||||
|
||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD
|
||||
./utils/acsmdownloader -f <ACSM_FILE>
|
||||
|
||||
|
||||
Copyright
|
||||
---------
|
||||
|
||||
Grégory Soutadé
|
||||
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
libgourou : LGPL v3 or later
|
||||
|
||||
utils : BSD
|
143
include/bytearray.h
Normal file
143
include/bytearray.h
Normal file
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _BYTEARRAY_H_
|
||||
#define _BYTEARRAY_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace gourou
|
||||
{
|
||||
/**
|
||||
* @brief Utility class for byte array management.
|
||||
*
|
||||
* It's an equivalent of QByteArray
|
||||
*
|
||||
* Data handled is first copied in a newly allocated buffer
|
||||
* and then shared between all copies until last object is destroyed
|
||||
*/
|
||||
class ByteArray
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Create an empty byte array
|
||||
*/
|
||||
ByteArray();
|
||||
|
||||
/**
|
||||
* @brief Initialize ByteArray with a copy of data
|
||||
*
|
||||
* @param data Data to be copied
|
||||
* @param length Length of data
|
||||
*/
|
||||
ByteArray(const unsigned char* data, unsigned int length);
|
||||
|
||||
/**
|
||||
* @brief Initialize ByteArray with a copy of data
|
||||
*
|
||||
* @param data Data to be copied
|
||||
* @param length Optional length of data. If length == -1, it use strlen(data) as length
|
||||
*/
|
||||
ByteArray(const char* data, int length=-1);
|
||||
|
||||
/**
|
||||
* @brief Initialize ByteArray with a copy of str
|
||||
*
|
||||
* @param str Use internal data of str
|
||||
*/
|
||||
ByteArray(const std::string& str);
|
||||
|
||||
ByteArray(const ByteArray& other);
|
||||
~ByteArray();
|
||||
|
||||
/**
|
||||
* @brief Encode "other" data into base64 and put it into a ByteArray
|
||||
*/
|
||||
static ByteArray fromBase64(const ByteArray& other);
|
||||
|
||||
/**
|
||||
* @brief Encode data into base64 and put it into a ByteArray
|
||||
*
|
||||
* @param data Data to be encoded
|
||||
* @param length Optional length of data. If length == -1, it use strlen(data) as length
|
||||
*/
|
||||
static ByteArray fromBase64(const char* data, int length=-1);
|
||||
|
||||
/**
|
||||
* @brief Encode str into base64 and put it into a ByteArray
|
||||
*
|
||||
* @param str Use internal data of str
|
||||
*/
|
||||
static ByteArray fromBase64(const std::string& str);
|
||||
|
||||
/**
|
||||
* @brief Return a string with base64 encoded internal data
|
||||
*/
|
||||
std::string toBase64();
|
||||
|
||||
/**
|
||||
* @brief Return a string with human readable hex encoded internal data
|
||||
*/
|
||||
std::string toHex();
|
||||
|
||||
/**
|
||||
* @brief Append a byte to internal data
|
||||
*/
|
||||
void append(unsigned char c);
|
||||
|
||||
/**
|
||||
* @brief Append data to internal data
|
||||
*/
|
||||
void append(const unsigned char* data, unsigned int length);
|
||||
|
||||
/**
|
||||
* @brief Append str to internal data
|
||||
*/
|
||||
void append(const char* str);
|
||||
|
||||
/**
|
||||
* @brief Append str to internal data
|
||||
*/
|
||||
void append(const std::string& str);
|
||||
|
||||
/**
|
||||
* @brief Get internal data. Must bot be modified nor freed
|
||||
*/
|
||||
const unsigned char* data() {return _data;}
|
||||
|
||||
/**
|
||||
* @brief Get internal data length
|
||||
*/
|
||||
unsigned int length() {return _length;}
|
||||
|
||||
ByteArray& operator=(const ByteArray& other);
|
||||
|
||||
private:
|
||||
void initData(const unsigned char* data, unsigned int length);
|
||||
void addRef();
|
||||
void delRef();
|
||||
|
||||
const unsigned char* _data;
|
||||
unsigned int _length;
|
||||
static std::map<const unsigned char*, int> refCounter;
|
||||
};
|
||||
}
|
||||
#endif
|
84
include/device.h
Normal file
84
include/device.h
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _DEVICE_H_
|
||||
#define _DEVICE_H_
|
||||
|
||||
namespace gourou
|
||||
{
|
||||
class DRMProcessor;
|
||||
|
||||
/**
|
||||
* @brief This class is a container for device.xml (device info) and devicesalt (device private key). It should not be used by user.
|
||||
*/
|
||||
class Device
|
||||
{
|
||||
public:
|
||||
static const int DEVICE_KEY_SIZE = 16;
|
||||
static const int DEVICE_SERIAL_LEN = 10;
|
||||
|
||||
/**
|
||||
* @brief Main Device constructor
|
||||
*
|
||||
* @param processor Instance of DRMProcessor
|
||||
* @param deviceFile Path of device.xml
|
||||
* @param deviceKeyFile Path of devicesalt
|
||||
*/
|
||||
Device(DRMProcessor* processor, const std::string& deviceFile, const std::string& deviceKeyFile);
|
||||
|
||||
/**
|
||||
* @brief Return value of devicesalt file (DEVICE_KEY_SIZE len)
|
||||
*/
|
||||
const unsigned char* getDeviceKey();
|
||||
|
||||
/**
|
||||
* @brief Get one value of device.xml (deviceClass, deviceSerial, deviceName, deviceType, jobbes, clientOS, clientLocale)
|
||||
*/
|
||||
std::string getProperty(const std::string& property, const std::string& _default=std::string(""));
|
||||
std::string operator[](const std::string& property);
|
||||
|
||||
/**
|
||||
* @brief Create device.xml and devicesalt files when they did not exists
|
||||
*
|
||||
* @param processor Instance of DRMProcessor
|
||||
* @param dirName Directory where to put files (.adept)
|
||||
* @param hobbes Hobbes (client version) to set
|
||||
* @param randomSerial Create a random serial (new device each time) or not (serial computed from machine specs)
|
||||
*/
|
||||
static Device* createDevice(DRMProcessor* processor, const std::string& dirName, const std::string& hobbes, bool randomSerial);
|
||||
|
||||
private:
|
||||
DRMProcessor* processor;
|
||||
std::string deviceFile;
|
||||
std::string deviceKeyFile;
|
||||
unsigned char deviceKey[DEVICE_KEY_SIZE];
|
||||
std::map<std::string, std::string> properties;
|
||||
|
||||
Device(DRMProcessor* processor);
|
||||
|
||||
std::string makeFingerprint(const std::string& serial);
|
||||
std::string makeSerial(bool random);
|
||||
void parseDeviceFile();
|
||||
void parseDeviceKeyFile();
|
||||
void createDeviceFile(const std::string& hobbes, bool randomSerial);
|
||||
void createDeviceKeyFile();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
350
include/drmprocessorclient.h
Normal file
350
include/drmprocessorclient.h
Normal file
|
@ -0,0 +1,350 @@
|
|||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _DRMPROCESSORCLIENT_H_
|
||||
#define _DRMPROCESSORCLIENT_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gourou
|
||||
{
|
||||
/**
|
||||
* @brief All fucntions that must be implemented by a client
|
||||
* This allow libgourou to have only few external libraries dependencies
|
||||
* and improve code portability
|
||||
*/
|
||||
|
||||
class DigestInterface
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Create a digest handler (for now only SHA1 is used)
|
||||
*
|
||||
* @param digestName Digest name to instanciate
|
||||
*/
|
||||
virtual void* createDigest(const std::string& digestName) = 0;
|
||||
|
||||
/**
|
||||
* @brief Update digest engine with new data
|
||||
*
|
||||
* @param handler Digest handler
|
||||
* @param data Data to digest
|
||||
* @param length Length of data
|
||||
*
|
||||
* @return OK/KO
|
||||
*/
|
||||
virtual int digestUpdate(void* handler, unsigned char* data, unsigned int length) = 0;
|
||||
|
||||
/**
|
||||
* @brief Finalize digest with remained buffered data and destroy handler
|
||||
*
|
||||
* @param handler Digest handler
|
||||
* @param digestOut Digest result (buffer must be pre allocated with right size)
|
||||
*
|
||||
* @return OK/KO
|
||||
*/
|
||||
virtual int digestFinalize(void* handler, unsigned char* digestOut) = 0;
|
||||
|
||||
/**
|
||||
* @brief Global digest function
|
||||
*
|
||||
* @param digestName Digest name to instanciate
|
||||
* @param data Data to digest
|
||||
* @param length Length of data
|
||||
* @param digestOut Digest result (buffer must be pre allocated with right size)
|
||||
*
|
||||
* @return OK/KO
|
||||
*/
|
||||
virtual int digest(const std::string& digestName, unsigned char* data, unsigned int length, unsigned char* digestOut) = 0;
|
||||
};
|
||||
|
||||
class RandomInterface
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Generate random bytes
|
||||
*
|
||||
* @param bytesOut Buffer to fill with random bytes
|
||||
* @param length Length of bytesOut
|
||||
*/
|
||||
virtual void randBytes(unsigned char* bytesOut, unsigned int length) = 0;
|
||||
};
|
||||
|
||||
class HTTPInterface
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
virtual std::string sendHTTPRequest(const std::string& URL, const std::string& POSTData=std::string(""), const std::string& contentType=std::string("")) = 0;
|
||||
};
|
||||
|
||||
class RSAInterface
|
||||
{
|
||||
public:
|
||||
enum RSA_KEY_TYPE {
|
||||
RSA_KEY_PKCS12 = 0,
|
||||
RSA_KEY_X509
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Encrypt data with RSA private key. Data is padded using PKCS1.5
|
||||
*
|
||||
* @param RSAKey RSA key in binary form
|
||||
* @param RSAKeyLength RSA key length
|
||||
* @param keyType Key type
|
||||
* @param password Optional password for RSA PKCS12 certificate
|
||||
* @param data Data to encrypt
|
||||
* @param dataLength Data length
|
||||
* @param res Encryption result (pre allocated buffer)
|
||||
*/
|
||||
virtual void RSAPrivateEncrypt(const unsigned char* RSAKey, unsigned int RSAKeyLength,
|
||||
const RSA_KEY_TYPE keyType, const std::string& password,
|
||||
const unsigned char* data, unsigned dataLength,
|
||||
unsigned char* res) = 0;
|
||||
|
||||
/**
|
||||
* @brief Encrypt data with RSA public key. Data is padded using PKCS1.5
|
||||
*
|
||||
* @param RSAKey RSA key in binary form
|
||||
* @param RSAKeyLength RSA key length
|
||||
* @param keyType Key type
|
||||
* @param password Optional password for RSA PKCS12 certificate
|
||||
* @param data Data to encrypt
|
||||
* @param dataLength Data length
|
||||
* @param res Encryption result (pre allocated buffer)
|
||||
*/
|
||||
virtual void RSAPublicEncrypt(const unsigned char* RSAKey, unsigned int RSAKeyLength,
|
||||
const RSA_KEY_TYPE keyType,
|
||||
const unsigned char* data, unsigned dataLength,
|
||||
unsigned char* res) = 0;
|
||||
|
||||
/**
|
||||
* @brief Generate RSA key. Expnonent is fixed (65537 / 0x10001)
|
||||
*
|
||||
* @param keyLengthBits Length of key (in bits) to generate
|
||||
*
|
||||
* @return generatedKey
|
||||
*/
|
||||
virtual void* generateRSAKey(int keyLengthBits) = 0;
|
||||
|
||||
/**
|
||||
* @brief Destroy key previously generated
|
||||
*
|
||||
* @param handler Key to destroy
|
||||
*/
|
||||
virtual void destroyRSAHandler(void* handler) = 0;
|
||||
|
||||
/**
|
||||
* @brief Extract public key (big number) from RSA handler
|
||||
*
|
||||
* @param handler RSA handler (generated key)
|
||||
* @param keyOut Pre allocated buffer (if *keyOut != 0). If *keyOut is 0, memory is internally allocated (must be freed)
|
||||
* @param keyOutLength Length of result
|
||||
*/
|
||||
virtual void extractRSAPublicKey(void* handler, unsigned char** keyOut, unsigned int* keyOutLength) = 0;
|
||||
|
||||
/**
|
||||
* @brief Extract private key (big number) from RSA handler
|
||||
*
|
||||
* @param handler RSA handler (generated key)
|
||||
* @param keyOut Pre allocated buffer (if *keyOut != 0). If *keyOut is 0, memory is internally allocated (must be freed)
|
||||
* @param keyOutLength Length of result
|
||||
*/
|
||||
virtual void extractRSAPrivateKey(void* handler, unsigned char** keyOut, unsigned int* keyOutLength) = 0;
|
||||
};
|
||||
|
||||
class CryptoInterface
|
||||
{
|
||||
public:
|
||||
enum CHAINING_MODE {
|
||||
CHAIN_ECB=0,
|
||||
CHAIN_CBC
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Do AES encryption. If length of data is not multiple of 16, PKCS#5 padding is done
|
||||
*
|
||||
* @param chaining Chaining mode
|
||||
* @param key AES key
|
||||
* @param keyLength AES key length
|
||||
* @param iv IV key
|
||||
* @param ivLength IV key length
|
||||
* @param dataIn Data to encrypt
|
||||
* @param dataInLength Data length
|
||||
* @param dataOut Encrypted data
|
||||
* @param dataOutLength Length of encrypted data
|
||||
*/
|
||||
virtual void AESEncrypt(CHAINING_MODE chaining,
|
||||
const unsigned char* key, unsigned int keyLength,
|
||||
const unsigned char* iv, unsigned int ivLength,
|
||||
const unsigned char* dataIn, unsigned int dataInLength,
|
||||
unsigned char* dataOut, unsigned int* dataOutLength) = 0;
|
||||
|
||||
/**
|
||||
* @brief Init AES CBC encryption
|
||||
*
|
||||
* @param chaining Chaining mode
|
||||
* @param key AES key
|
||||
* @param keyLength AES key length
|
||||
* @param iv IV key
|
||||
* @param ivLength IV key length
|
||||
*
|
||||
* @return AES handler
|
||||
*/
|
||||
virtual void* AESEncryptInit(CHAINING_MODE chaining,
|
||||
const unsigned char* key, unsigned int keyLength,
|
||||
const unsigned char* iv=0, unsigned int ivLength=0) = 0;
|
||||
|
||||
/**
|
||||
* @brief Encrypt data
|
||||
*
|
||||
* @param handler AES handler
|
||||
* @param dataIn Data to encrypt
|
||||
* @param dataInLength Data length
|
||||
* @param dataOut Encrypted data
|
||||
* @param dataOutLength Length of encrypted data
|
||||
*/
|
||||
virtual void AESEncryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
|
||||
unsigned char* dataOut, unsigned int* dataOutLength) = 0;
|
||||
|
||||
/**
|
||||
* @brief Finalize AES encryption (pad and encrypt last block if needed)
|
||||
* Destroy handler at the end
|
||||
*
|
||||
* @param handler AES handler
|
||||
* @param dataOut Last block of encrypted data
|
||||
* @param dataOutLength Length of encrypted data
|
||||
*/
|
||||
virtual void AESEncryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength) = 0;
|
||||
|
||||
/**
|
||||
* @brief Do AES decryption. If length of data is not multiple of 16, PKCS#5 padding is done
|
||||
*
|
||||
* @param chaining Chaining mode
|
||||
* @param key AES key
|
||||
* @param keyLength AES key length
|
||||
* @param iv IV key
|
||||
* @param ivLength IV key length
|
||||
* @param dataIn Data to encrypt
|
||||
* @param dataInLength Data length
|
||||
* @param dataOut Encrypted data
|
||||
* @param dataOutLength Length of encrypted data
|
||||
*/
|
||||
virtual void AESDecrypt(CHAINING_MODE chaining,
|
||||
const unsigned char* key, unsigned int keyLength,
|
||||
const unsigned char* iv, unsigned int ivLength,
|
||||
const unsigned char* dataIn, unsigned int dataInLength,
|
||||
unsigned char* dataOut, unsigned int* dataOutLength) = 0;
|
||||
|
||||
/**
|
||||
* @brief Init AES decryption
|
||||
*
|
||||
* @param chaining Chaining mode
|
||||
* @param key AES key
|
||||
* @param keyLength AES key length
|
||||
* @param iv IV key
|
||||
* @param ivLength IV key length
|
||||
*
|
||||
* @return AES handler
|
||||
*/
|
||||
virtual void* AESDecryptInit(CHAINING_MODE chaining,
|
||||
const unsigned char* key, unsigned int keyLength,
|
||||
const unsigned char* iv=0, unsigned int ivLength=0) = 0;
|
||||
|
||||
/**
|
||||
* @brief Decrypt data
|
||||
*
|
||||
* @param handler AES handler
|
||||
* @param dataIn Data to decrypt
|
||||
* @param dataInLength Data length
|
||||
* @param dataOut Decrypted data
|
||||
* @param dataOutLength Length of decrypted data
|
||||
*/
|
||||
virtual void AESDecryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
|
||||
unsigned char* dataOut, unsigned int* dataOutLength) = 0;
|
||||
/**
|
||||
* @brief Finalize AES decryption (decrypt last block and remove padding if it is set).
|
||||
* Destroy handler at the end
|
||||
*
|
||||
* @param handler AES handler
|
||||
* @param dataOut Last block decrypted data
|
||||
* @param dataOutLength Length of decrypted data
|
||||
*/
|
||||
virtual void AESDecryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength) = 0;
|
||||
};
|
||||
|
||||
|
||||
class ZIPInterface
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Open a zip file and return an handler
|
||||
*
|
||||
* @param path Path of zip file
|
||||
*
|
||||
* @return ZIP file handler
|
||||
*/
|
||||
virtual void* zipOpen(const std::string& path) = 0;
|
||||
|
||||
/**
|
||||
* @brief Read zip internal file
|
||||
*
|
||||
* @param handler ZIP file handler
|
||||
* @param path Internal path inside zip file
|
||||
*
|
||||
* @return File content
|
||||
*/
|
||||
virtual std::string zipReadFile(void* handler, const std::string& path) = 0;
|
||||
|
||||
/**
|
||||
* @brief Write zip internal file
|
||||
*
|
||||
* @param handler ZIP file handler
|
||||
* @param path Internal path inside zip file
|
||||
* @param content Internal file content
|
||||
*/
|
||||
virtual void zipWriteFile(void* handler, const std::string& path, const std::string& content) = 0;
|
||||
|
||||
/**
|
||||
* @brief Delete zip internal file
|
||||
*
|
||||
* @param handler ZIP file handler
|
||||
* @param path Internal path inside zip file
|
||||
*/
|
||||
virtual void zipDeleteFile(void* handler, const std::string& path) = 0;
|
||||
|
||||
/**
|
||||
* @brief Close ZIP file handler
|
||||
*
|
||||
* @param handler ZIP file handler
|
||||
*/
|
||||
virtual void zipClose(void* handler) = 0;
|
||||
};
|
||||
|
||||
class DRMProcessorClient: public DigestInterface, public RandomInterface, public HTTPInterface, \
|
||||
public RSAInterface, public CryptoInterface, public ZIPInterface
|
||||
{};
|
||||
}
|
||||
#endif
|
65
include/fulfillment_item.h
Normal file
65
include/fulfillment_item.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _FULFILLMENT_ITEM_H_
|
||||
#define _FULFILLMENT_ITEM_H_
|
||||
|
||||
#include "bytearray.h"
|
||||
|
||||
#include <pugixml.hpp>
|
||||
|
||||
namespace gourou
|
||||
{
|
||||
class User;
|
||||
|
||||
/**
|
||||
* @brief This class is a container for a fulfillment object
|
||||
*/
|
||||
class FulfillmentItem
|
||||
{
|
||||
public:
|
||||
FulfillmentItem(pugi::xml_document& doc, User* user);
|
||||
|
||||
/**
|
||||
* @brief Return metadata value from ACSM metadata section
|
||||
*
|
||||
* @param name Name of key to return
|
||||
*/
|
||||
std::string getMetadata(std::string name);
|
||||
|
||||
/**
|
||||
* @brief Return rights generated by ACS server (XML format)
|
||||
*/
|
||||
std::string getRights();
|
||||
|
||||
/**
|
||||
* @brief Return epub download URL
|
||||
*/
|
||||
std::string getDownloadURL();
|
||||
|
||||
private:
|
||||
pugi::xml_node metadatas;
|
||||
pugi::xml_document rights;
|
||||
std::string downloadURL;
|
||||
|
||||
void buildRights(const pugi::xml_node& licenseToken, User* user);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
190
include/libgourou.h
Normal file
190
include/libgourou.h
Normal file
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _LIBGOUROU_H_
|
||||
#define _LIBGOUROU_H_
|
||||
|
||||
#include "bytearray.h"
|
||||
#include "device.h"
|
||||
#include "user.h"
|
||||
#include "fulfillment_item.h"
|
||||
#include "drmprocessorclient.h"
|
||||
|
||||
#include <pugixml.hpp>
|
||||
|
||||
#ifndef HOBBES_DEFAULT_VERSION
|
||||
#define HOBBES_DEFAULT_VERSION "10.0.4"
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_ADEPT_DIR
|
||||
#define DEFAULT_ADEPT_DIR "./.adept"
|
||||
#endif
|
||||
|
||||
#ifndef ACS_SERVER
|
||||
#define ACS_SERVER "http://adeactivate.adobe.com/adept"
|
||||
#endif
|
||||
|
||||
namespace gourou
|
||||
{
|
||||
/**
|
||||
* @brief Main class that handle all ADEPTS functions (fulfill, download, signIn, activate)
|
||||
*/
|
||||
class DRMProcessor
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @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
|
||||
*
|
||||
* @return a FulfillmentItem if all is OK
|
||||
*/
|
||||
FulfillmentItem* fulfill(const std::string& ACSMFile);
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
void download(FulfillmentItem* item, std::string path);
|
||||
|
||||
/**
|
||||
* @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 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, const std::string& dirName=std::string(DEFAULT_ADEPT_DIR),
|
||||
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
|
||||
*/
|
||||
ByteArray sendRequest(const std::string& URL, const std::string& POSTData=std::string(), const char* contentType=0);
|
||||
|
||||
/**
|
||||
* @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 Get current user
|
||||
*/
|
||||
User* getUser() { return user; }
|
||||
|
||||
/**
|
||||
* @brief Get current device
|
||||
*/
|
||||
Device* getDevice() { return device; }
|
||||
|
||||
/**
|
||||
* @brief Get current client
|
||||
*/
|
||||
DRMProcessorClient* getClient() { return client; }
|
||||
|
||||
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<std::string,std::string> nsHash);
|
||||
void hashNode(const pugi::xml_node& root, unsigned char* sha_out);
|
||||
void buildFulfillRequest(pugi::xml_document& acsmDoc, pugi::xml_document& fulfillReq);
|
||||
void buildActivateReq(pugi::xml_document& activateReq);
|
||||
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);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
350
include/libgourou_common.h
Normal file
350
include/libgourou_common.h
Normal file
|
@ -0,0 +1,350 @@
|
|||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _LIBGOUROU_COMMON_H_
|
||||
#define _LIBGOUROU_COMMON_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <pugixml.hpp>
|
||||
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <algorithm>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <libgourou_log.h>
|
||||
#include "bytearray.h"
|
||||
|
||||
namespace gourou
|
||||
{
|
||||
/**
|
||||
* Some common utilities
|
||||
*/
|
||||
|
||||
#define ADOBE_ADEPT_NS "http://ns.adobe.com/adept"
|
||||
|
||||
static const int SHA1_LEN = 20;
|
||||
static const int RSA_KEY_SIZE = 128;
|
||||
static const int RSA_KEY_SIZE_BITS = (RSA_KEY_SIZE*8);
|
||||
|
||||
enum GOUROU_ERROR {
|
||||
GOUROU_DEVICE_DOES_NOT_MATCH = 0x1000,
|
||||
GOUROU_INVALID_CLIENT,
|
||||
GOUROU_TAG_NOT_FOUND,
|
||||
GOUROU_ADEPT_ERROR,
|
||||
GOUROU_FILE_ERROR
|
||||
};
|
||||
|
||||
enum FULFILL_ERROR {
|
||||
FF_ACSM_FILE_NOT_EXISTS = 0x1100,
|
||||
FF_INVALID_ACSM_FILE,
|
||||
FF_NO_HMAC_IN_ACSM_FILE,
|
||||
FF_NOT_ACTIVATED,
|
||||
FF_NO_OPERATOR_URL
|
||||
};
|
||||
|
||||
enum DOWNLOAD_ERROR {
|
||||
DW_NO_ITEM = 0x1200,
|
||||
};
|
||||
|
||||
enum SIGNIN_ERROR {
|
||||
SIGN_INVALID_CREDENTIALS = 0x1300,
|
||||
};
|
||||
|
||||
enum ACTIVATE_ERROR {
|
||||
ACTIVATE_NOT_SIGNEDIN = 0x1400
|
||||
};
|
||||
|
||||
enum DEV_ERROR {
|
||||
DEV_MKPATH = 0x2000,
|
||||
DEV_MAC_ERROR,
|
||||
DEV_INVALID_DEVICE_FILE,
|
||||
DEV_INVALID_DEVICE_KEY_FILE,
|
||||
DEV_INVALID_DEV_PROPERTY,
|
||||
};
|
||||
|
||||
enum USER_ERROR {
|
||||
USER_MKPATH = 0x3000,
|
||||
USER_INVALID_ACTIVATION_FILE,
|
||||
USER_NO_AUTHENTICATION_URL,
|
||||
USER_NO_PROPERTY,
|
||||
};
|
||||
|
||||
enum FULFILL_ITEM_ERROR {
|
||||
FFI_INVALID_FULFILLMENT_DATA = 0x4000
|
||||
};
|
||||
|
||||
enum CLIENT_ERROR {
|
||||
CLIENT_BAD_PARAM = 0x5000,
|
||||
CLIENT_INVALID_PKCS12,
|
||||
CLIENT_INVALID_CERTIFICATE,
|
||||
CLIENT_NO_PRIV_KEY,
|
||||
CLIENT_RSA_ERROR,
|
||||
CLIENT_BAD_CHAINING,
|
||||
CLIENT_BAD_KEY_SIZE,
|
||||
CLIENT_BAD_ZIP_FILE,
|
||||
CLIENT_ZIP_ERROR,
|
||||
CLIENT_GENERIC_EXCEPTION
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Generic exception class
|
||||
*/
|
||||
class Exception : public std::exception
|
||||
{
|
||||
public:
|
||||
Exception(int code, const char* message, const char* file, int line):
|
||||
code(code), line(line), file(file)
|
||||
{
|
||||
std::stringstream msg;
|
||||
msg << "Exception code : 0x" << std::setbase(16) << code << std::endl;
|
||||
msg << "Message : " << message << std::endl;
|
||||
if (logLevel >= DEBUG)
|
||||
msg << "File : " << file << ":" << std::setbase(10) << line << std::endl;
|
||||
fullmessage = strdup(msg.str().c_str());
|
||||
}
|
||||
|
||||
~Exception()
|
||||
{
|
||||
free(fullmessage);
|
||||
}
|
||||
|
||||
const char * what () const throw () { return fullmessage; }
|
||||
|
||||
int getErrorCode() {return code;}
|
||||
|
||||
private:
|
||||
int code, line;
|
||||
const char* message, *file;
|
||||
char* fullmessage;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Throw an exception
|
||||
*/
|
||||
#define EXCEPTION(code, message) \
|
||||
{std::stringstream __msg;__msg << message; throw gourou::Exception(code, __msg.str().c_str(), __FILE__, __LINE__);}
|
||||
|
||||
/**
|
||||
* Stream writer for pugi::xml
|
||||
*/
|
||||
class StringXMLWriter : public pugi::xml_writer
|
||||
{
|
||||
public:
|
||||
virtual void write(const void* data, size_t size)
|
||||
{
|
||||
result.append(static_cast<const char*>(data), size);
|
||||
}
|
||||
|
||||
const std::string& getResult() {return result;}
|
||||
|
||||
private:
|
||||
std::string result;
|
||||
};
|
||||
|
||||
static const char* ws = " \t\n\r\f\v";
|
||||
|
||||
/**
|
||||
* @brief trim from end of string (right)
|
||||
*/
|
||||
inline std::string& rtrim(std::string& s, const char* t = ws)
|
||||
{
|
||||
s.erase(s.find_last_not_of(t) + 1);
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief trim from beginning of string (left)
|
||||
*/
|
||||
inline std::string& ltrim(std::string& s, const char* t = ws)
|
||||
{
|
||||
s.erase(0, s.find_first_not_of(t));
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief trim from both ends of string (right then left)
|
||||
*/
|
||||
inline std::string& trim(std::string& s, const char* t = ws)
|
||||
{
|
||||
return ltrim(rtrim(s, t), t);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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_document& doc, const char* tagName, bool throwOnNull=true)
|
||||
{
|
||||
pugi::xpath_node xpath_node = doc.select_node(tagName);
|
||||
|
||||
if (!xpath_node)
|
||||
{
|
||||
if (throwOnNull)
|
||||
EXCEPTION(GOUROU_TAG_NOT_FOUND, "Tag " << tagName << " not found");
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
pugi::xml_node node = xpath_node.node().first_child();
|
||||
|
||||
if (!node)
|
||||
{
|
||||
if (throwOnNull)
|
||||
EXCEPTION(GOUROU_TAG_NOT_FOUND, "Text element for tag " << tagName << " not found");
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string res = node.value();
|
||||
return trim(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Append an element to root with a sub text element
|
||||
*
|
||||
* @param root Root node where to put child
|
||||
* @param name Tag name for child
|
||||
* @param value Text child value of tag element
|
||||
*/
|
||||
static inline void appendTextElem(pugi::xml_node& root, const std::string& name, const std::string& value)
|
||||
{
|
||||
pugi::xml_node node = root.append_child(name.c_str());
|
||||
node.append_child(pugi::node_pcdata).set_value(value.c_str());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write data in a file. If it already exists, it's truncated
|
||||
*/
|
||||
static inline void writeFile(std::string path, const unsigned char* data, unsigned int length)
|
||||
{
|
||||
int fd = open(path.c_str(), O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
|
||||
|
||||
if (fd <= 0)
|
||||
EXCEPTION(GOUROU_FILE_ERROR, "Unable to create " << path);
|
||||
|
||||
if (write(fd, data, length) != length)
|
||||
EXCEPTION(GOUROU_FILE_ERROR, "Write error for file " << path);
|
||||
|
||||
close (fd);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write data in a file. If it already exists, it's truncated
|
||||
*/
|
||||
static inline void writeFile(std::string path, ByteArray& data)
|
||||
{
|
||||
writeFile(path, data.data(), data.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write data in a file. If it already exists, it's truncated
|
||||
*/
|
||||
static inline void writeFile(std::string path, const std::string& data)
|
||||
{
|
||||
writeFile(path, (const unsigned char*)data.c_str(), data.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Read data from file
|
||||
*/
|
||||
static inline void readFile(std::string path, const unsigned char* data, unsigned int length)
|
||||
{
|
||||
int fd = open(path.c_str(), O_RDONLY);
|
||||
|
||||
if (fd <= 0)
|
||||
EXCEPTION(GOUROU_FILE_ERROR, "Unable to open " << path);
|
||||
|
||||
if (read(fd, (void*)data, length) != length)
|
||||
EXCEPTION(GOUROU_FILE_ERROR, "Read error for file " << path);
|
||||
|
||||
close (fd);
|
||||
}
|
||||
|
||||
#define PATH_MAX_STRING_SIZE 256
|
||||
|
||||
// https://gist.github.com/ChisholmKyle/0cbedcd3e64132243a39
|
||||
/* recursive mkdir */
|
||||
static inline int mkdir_p(const char *dir, const mode_t mode) {
|
||||
char tmp[PATH_MAX_STRING_SIZE];
|
||||
char *p = NULL;
|
||||
struct stat sb;
|
||||
size_t len;
|
||||
|
||||
/* copy path */
|
||||
len = strnlen (dir, PATH_MAX_STRING_SIZE);
|
||||
if (len == 0 || len == PATH_MAX_STRING_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
memcpy (tmp, dir, len);
|
||||
tmp[len] = '\0';
|
||||
|
||||
/* remove trailing slash */
|
||||
if(tmp[len - 1] == '/') {
|
||||
tmp[len - 1] = '\0';
|
||||
}
|
||||
|
||||
/* check if path exists and is a directory */
|
||||
if (stat (tmp, &sb) == 0) {
|
||||
if (S_ISDIR (sb.st_mode)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* recursive mkdir */
|
||||
for(p = tmp + 1; *p; p++) {
|
||||
if(*p == '/') {
|
||||
*p = 0;
|
||||
/* test path */
|
||||
if (stat(tmp, &sb) != 0) {
|
||||
/* path does not exist - create directory */
|
||||
if (mkdir(tmp, mode) < 0) {
|
||||
return -1;
|
||||
}
|
||||
} else if (!S_ISDIR(sb.st_mode)) {
|
||||
/* not a directory */
|
||||
return -1;
|
||||
}
|
||||
*p = '/';
|
||||
}
|
||||
}
|
||||
/* test path */
|
||||
if (stat(tmp, &sb) != 0) {
|
||||
/* path does not exist - create directory */
|
||||
if (mkdir(tmp, mode) < 0) {
|
||||
return -1;
|
||||
}
|
||||
} else if (!S_ISDIR(sb.st_mode)) {
|
||||
/* not a directory */
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
50
include/libgourou_log.h
Normal file
50
include/libgourou_log.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _LIBGOUROU_LOG_H_
|
||||
#define _LIBGOUROU_LOG_H_
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace gourou {
|
||||
enum GOUROU_LOG_LEVEL {
|
||||
ERROR,
|
||||
WARN,
|
||||
INFO,
|
||||
DEBUG,
|
||||
TRACE
|
||||