mirror of
https://forge.soutade.fr/soutade/libgourou.git
synced 2026-03-27 01:36:58 +00:00
Compare commits
No commits in common. "master" and "v0.7.2" have entirely different histories.
36 changed files with 3770 additions and 4999 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,6 +1,5 @@
|
||||||
obj
|
obj
|
||||||
lib
|
lib
|
||||||
*.o
|
|
||||||
*.a
|
*.a
|
||||||
*.so
|
*.so
|
||||||
*~
|
*~
|
||||||
|
|
|
||||||
88
Makefile
88
Makefile
|
|
@ -1,41 +1,22 @@
|
||||||
PREFIX ?= /usr/local
|
|
||||||
LIBDIR ?= /lib
|
|
||||||
INCDIR ?= /include
|
|
||||||
|
|
||||||
AR ?= $(CROSS)ar
|
AR ?= $(CROSS)ar
|
||||||
CXX ?= $(CROSS)g++
|
CXX ?= $(CROSS)g++
|
||||||
|
|
||||||
UPDFPARSERLIB = ./lib/updfparser/libupdfparser.a
|
UPDFPARSERLIB = ./lib/updfparser/libupdfparser.a
|
||||||
|
|
||||||
CXXFLAGS += -Wall -fPIC -I./include -I./usr/include/pugixml -I./lib/updfparser/include
|
CXXFLAGS=-Wall -fPIC -I./include -I./lib -I./lib/pugixml/src/ -I./lib/updfparser/include
|
||||||
LDFLAGS = -lpugixml
|
LDFLAGS = $(UPDFPARSERLIB)
|
||||||
|
|
||||||
VERSION := $(shell cat include/libgourou.h |grep LIBGOUROU_VERSION|cut -d '"' -f2)
|
|
||||||
|
|
||||||
UNAME := $(shell uname -s)
|
|
||||||
|
|
||||||
BUILD_STATIC ?= 0
|
BUILD_STATIC ?= 0
|
||||||
BUILD_SHARED ?= 1
|
BUILD_SHARED ?= 1
|
||||||
BUILD_UTILS ?= 1
|
BUILD_UTILS ?= 1
|
||||||
|
|
||||||
TARGETS =
|
TARGETS =
|
||||||
TARGET_LIBRARIES =
|
|
||||||
ifneq ($(STATIC_UTILS),)
|
|
||||||
BUILD_STATIC=1
|
|
||||||
endif
|
|
||||||
ifneq ($(BUILD_STATIC), 0)
|
ifneq ($(BUILD_STATIC), 0)
|
||||||
TARGETS += libgourou.a
|
TARGETS += libgourou.a
|
||||||
TARGET_LIBRARIES += libgourou.a
|
|
||||||
STATIC_UTILS=1
|
|
||||||
endif
|
endif
|
||||||
ifneq ($(BUILD_SHARED), 0)
|
ifneq ($(BUILD_SHARED), 0)
|
||||||
ifeq ($(UNAME), Darwin)
|
TARGETS += libgourou.so
|
||||||
TARGETS += libgourou.dylib
|
|
||||||
TARGET_LIBRARIES += libgourou.dylib libgourou.dylib.$(VERSION)
|
|
||||||
else
|
|
||||||
TARGETS += libgourou.so
|
|
||||||
TARGET_LIBRARIES += libgourou.so libgourou.so.$(VERSION)
|
|
||||||
endif
|
|
||||||
endif
|
endif
|
||||||
ifneq ($(BUILD_UTILS), 0)
|
ifneq ($(BUILD_UTILS), 0)
|
||||||
TARGETS += build_utils
|
TARGETS += build_utils
|
||||||
|
|
@ -43,83 +24,48 @@ endif
|
||||||
|
|
||||||
|
|
||||||
ifneq ($(DEBUG),)
|
ifneq ($(DEBUG),)
|
||||||
CXXFLAGS += -ggdb -O0 -DDEBUG
|
CXXFLAGS += -ggdb -O0
|
||||||
else
|
else
|
||||||
CXXFLAGS += -O2
|
CXXFLAGS += -O2
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq ($(STATIC_NONCE),)
|
|
||||||
CXXFLAGS += -DSTATIC_NONCE=1
|
|
||||||
endif
|
|
||||||
|
|
||||||
SRCDIR := src
|
SRCDIR := src
|
||||||
|
INCDIR := inc
|
||||||
BUILDDIR := obj
|
BUILDDIR := obj
|
||||||
|
TARGETDIR := bin
|
||||||
SRCEXT := cpp
|
SRCEXT := cpp
|
||||||
OBJEXT := o
|
OBJEXT := o
|
||||||
|
|
||||||
SOURCES = src/libgourou.cpp src/user.cpp src/device.cpp src/fulfillment_item.cpp src/loan_token.cpp src/bytearray.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)))
|
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.$(OBJEXT)))
|
||||||
|
|
||||||
all: version lib obj $(TARGETS)
|
all: lib obj $(TARGETS)
|
||||||
|
|
||||||
version:
|
|
||||||
@echo "Building libgourou $(VERSION)"
|
|
||||||
|
|
||||||
lib:
|
lib:
|
||||||
mkdir lib
|
mkdir lib
|
||||||
./scripts/setup.sh
|
./scripts/setup.sh
|
||||||
|
|
||||||
update_lib:
|
|
||||||
./scripts/update_lib.sh
|
|
||||||
|
|
||||||
obj:
|
obj:
|
||||||
mkdir obj
|
mkdir obj
|
||||||
|
|
||||||
$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT)
|
$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT)
|
||||||
$(CXX) $(CXXFLAGS) -c $^ -o $@
|
$(CXX) $(CXXFLAGS) -c $^ -o $@
|
||||||
|
|
||||||
libgourou: $(TARGET_LIBRARIES)
|
libgourou: libgourou.a libgourou.so
|
||||||
|
|
||||||
libgourou.a: $(OBJECTS) $(UPDFPARSERLIB)
|
libgourou.a: $(OBJECTS) $(UPDFPARSERLIB)
|
||||||
$(AR) rcs --thin $@ $^
|
$(AR) crs $@ obj/*.o $(UPDFPARSERLIB)
|
||||||
|
|
||||||
libgourou.so.$(VERSION): $(OBJECTS) $(UPDFPARSERLIB)
|
libgourou.so: $(OBJECTS) $(UPDFPARSERLIB)
|
||||||
$(CXX) $^ -Wl,-soname,$@ $(LDFLAGS) -o $@ -shared
|
$(CXX) obj/*.o $(LDFLAGS) -o $@ -shared
|
||||||
|
|
||||||
libgourou.so: libgourou.so.$(VERSION)
|
build_utils:
|
||||||
ln -f -s $^ $@
|
make -C utils ROOT=$(PWD) CXX=$(CXX) AR=$(AR) DEBUG=$(DEBUG) STATIC_UTILS=$(STATIC_UTILS) OPENSSL3=$(OPENSSL3)
|
||||||
|
|
||||||
libgourou.dylib.$(VERSION): $(OBJECTS) $(UPDFPARSERLIB)
|
|
||||||
$(CXX) $^ $(LDFLAGS) -o $@ -shared
|
|
||||||
|
|
||||||
libgourou.dylib: libgourou.dylib.$(VERSION)
|
|
||||||
ln -f -s $^ $@
|
|
||||||
|
|
||||||
build_utils: $(TARGET_LIBRARIES)
|
|
||||||
$(MAKE) -C utils ROOT=$(PWD) CXX=$(CXX) AR=$(AR) DEBUG=$(DEBUG) STATIC_UTILS=$(STATIC_UTILS) DESTDIR=$(DESTDIR) PREFIX=$(PREFIX)
|
|
||||||
|
|
||||||
install: $(TARGET_LIBRARIES)
|
|
||||||
install -d $(DESTDIR)$(PREFIX)$(LIBDIR)
|
|
||||||
# Use cp to preserver symlinks
|
|
||||||
cp --no-dereference $(TARGET_LIBRARIES) $(DESTDIR)$(PREFIX)$(LIBDIR)
|
|
||||||
$(MAKE) -C utils ROOT=$(PWD) CXX=$(CXX) AR=$(AR) DEBUG=$(DEBUG) STATIC_UTILS=$(STATIC_UTILS) DESTDIR=$(DESTDIR) PREFIX=$(PREFIX) install
|
|
||||||
|
|
||||||
uninstall:
|
|
||||||
cd $(DESTDIR)$(PREFIX)/$(LIBDIR)
|
|
||||||
rm -f $(TARGET_LIBRARIES) libgourou.so.$(VERSION)
|
|
||||||
cd -
|
|
||||||
|
|
||||||
install_headers:
|
|
||||||
install -d $(DESTDIR)$(PREFIX)/$(INCDIR)/libgourou
|
|
||||||
cp --no-dereference include/*.h $(DESTDIR)$(PREFIX)/$(INCDIR)/libgourou
|
|
||||||
|
|
||||||
uninstall_headers:
|
|
||||||
rm -rf $(DESTDIR)$(PREFIX)/$(INCDIR)/libgourou
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf libgourou.a libgourou.so libgourou.so.$(VERSION)* obj
|
rm -rf libgourou.a libgourou.so obj
|
||||||
$(MAKE) -C utils clean
|
make -C utils clean
|
||||||
|
|
||||||
ultraclean: clean
|
ultraclean: clean
|
||||||
rm -rf lib
|
rm -rf lib
|
||||||
$(MAKE) -C utils ultraclean
|
make -C utils ultraclean
|
||||||
|
|
|
||||||
100
README.md
100
README.md
|
|
@ -1,16 +1,16 @@
|
||||||
Introduction
|
Introduction
|
||||||
------------
|
------------
|
||||||
|
|
||||||
libgourou is a free implementation of Adobe's ADEPT protocol used to add DRM on ePub/PDF files. It overcomes the lack of Adobe support for Linux platforms.
|
libgourou is a free implementation of Adobe's ADEPT protocol used to add DRM on ePub/PDF files. It overcome the lacks of Adobe support for Linux platforms.
|
||||||
|
|
||||||
|
|
||||||
Architecture
|
Architecture
|
||||||
------------
|
------------
|
||||||
|
|
||||||
Like RMSDK, libgourou has a client/server scheme. All platform specific functions (crypto, network...) have to be implemented in a client class (that derives from DRMProcessorClient) while server implements ADEPT protocol.
|
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 cURL, OpenSSL and libzip is provided (in _utils_ directory).
|
A reference implementation using Qt, OpenSSL and libzip is provided (in _utils_ directory).
|
||||||
|
|
||||||
Main functions to use from gourou::DRMProcessor are:
|
Main fucntions to use from gourou::DRMProcessor are :
|
||||||
|
|
||||||
* Get an ePub from an ACSM file : _fulfill()_ and _download()_
|
* Get an ePub from an ACSM file : _fulfill()_ and _download()_
|
||||||
* Create a new device : _createDRMProcessor()_
|
* Create a new device : _createDRMProcessor()_
|
||||||
|
|
@ -18,45 +18,30 @@ Main functions to use from gourou::DRMProcessor are:
|
||||||
* Remove DRM : _removeDRM()_
|
* Remove DRM : _removeDRM()_
|
||||||
* Return loaned book : _returnLoan()_
|
* Return loaned book : _returnLoan()_
|
||||||
|
|
||||||
You can import configuration from (at least):
|
You can import configuration from (at least) :
|
||||||
|
|
||||||
* Kobo device : .adept/device.xml, .adept/devicesalt and .adept/activation.xml
|
* 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
|
* 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 by one account.
|
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.
|
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.
|
||||||
|
|
||||||
For those who want to remove DRM without adept_remove, you can export your private key and import it within [Calibre](https://calibre-ebook.com/) an its DeDRM plugin.
|
For those who wants to remove DRM without adept_remove, you can export your private key and import it within [Calibre](https://calibre-ebook.com/) an its DeDRM plugin.
|
||||||
|
|
||||||
|
|
||||||
Dependencies
|
Dependencies
|
||||||
------------
|
------------
|
||||||
|
|
||||||
For libgourou:
|
For libgourou :
|
||||||
|
|
||||||
_externals_ :
|
* None
|
||||||
|
|
||||||
* libpugixml
|
For utils :
|
||||||
|
|
||||||
_internals_:
|
|
||||||
|
|
||||||
* uPDFParser
|
|
||||||
|
|
||||||
For utils:
|
|
||||||
|
|
||||||
* libcurl
|
* libcurl
|
||||||
* openssl
|
* OpenSSL
|
||||||
* libzip
|
* libzip
|
||||||
* libpugixml
|
|
||||||
|
|
||||||
|
|
||||||
External & utils dependencies has to be installed by your package manager (_apt_ for example).
|
|
||||||
Use _-dev_ flavours to get needed headers.
|
|
||||||
Internal libraries are automatically fetched and statically compiled during the first compilation.
|
|
||||||
When you update libgourou's repository, **don't forget to update internal libraries** with:
|
|
||||||
|
|
||||||
make update_lib
|
|
||||||
|
|
||||||
|
|
||||||
Compilation
|
Compilation
|
||||||
|
|
@ -64,7 +49,7 @@ Compilation
|
||||||
|
|
||||||
Use _make_ command
|
Use _make_ command
|
||||||
|
|
||||||
make [CROSS=XXX] [DEBUG=(0*|1)] [STATIC_UTILS=(0*|1)] [BUILD_UTILS=(0|1*)] [BUILD_STATIC=(0*|1)] [BUILD_SHARED=(0|1*)] [all*|clean|ultraclean|build_utils|install|uninstall]
|
make [CROSS=XXX] [DEBUG=(0*|1)] [STATIC_UTILS=(0*|1)] [BUILD_UTILS=(0|1*)] [BUILD_STATIC=(0*|1)] [BUILD_SHARED=(0|1*)]
|
||||||
|
|
||||||
CROSS can define a cross compiler prefix (ie arm-linux-gnueabihf-)
|
CROSS can define a cross compiler prefix (ie arm-linux-gnueabihf-)
|
||||||
|
|
||||||
|
|
@ -78,60 +63,47 @@ BUILD_STATIC build libgourou.a if 1, nothing if 0, can be combined with BUILD_SH
|
||||||
|
|
||||||
BUILD_SHARED build libgourou.so if 1, nothing if 0, can be combined with BUILD_STATIC
|
BUILD_SHARED build libgourou.so if 1, nothing if 0, can be combined with BUILD_STATIC
|
||||||
|
|
||||||
other variables are DESTDIR and PREFIX to handle destination install directory
|
|
||||||
|
|
||||||
* Default value
|
* Default value
|
||||||
|
|
||||||
|
|
||||||
Utils
|
Utils
|
||||||
-----
|
-----
|
||||||
|
|
||||||
First, add libgourou.so to your LD_LIBRARY_PATH
|
You can import configuration from your eReader or create a new one with _utils/adept\_activate_ :
|
||||||
|
|
||||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD
|
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD
|
||||||
|
|
||||||
You can optionaly specify your .adept directory
|
|
||||||
|
|
||||||
export ADEPT_DIR=/home/XXX
|
|
||||||
|
|
||||||
Then, use utils as following:
|
|
||||||
|
|
||||||
You can import configuration from your eReader or create a new one with _utils/adept\_activate_:
|
|
||||||
|
|
||||||
./utils/adept_activate -u <AdobeID USERNAME>
|
./utils/adept_activate -u <AdobeID USERNAME>
|
||||||
|
|
||||||
Then a _/home/<user>/.config/adept_ directory is created with all configuration file
|
Then a _./.adept_ directory is created with all configuration file
|
||||||
|
|
||||||
To download an ePub/PDF:
|
To download an ePub/PDF :
|
||||||
|
|
||||||
./utils/acsmdownloader <ACSM_FILE>
|
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD
|
||||||
|
./utils/acsmdownloader -f <ACSM_FILE>
|
||||||
|
|
||||||
To export your private key (for DeDRM software):
|
To export your private key (for DeDRM software) :
|
||||||
|
|
||||||
|
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD
|
||||||
./utils/acsmdownloader --export-private-key [-o adobekey_1.der]
|
./utils/acsmdownloader --export-private-key [-o adobekey_1.der]
|
||||||
|
|
||||||
To remove ADEPT DRM:
|
To remove ADEPT DRM :
|
||||||
|
|
||||||
./utils/adept_remove <encryptedFile>
|
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD
|
||||||
|
./utils/adept_remove -f <encryptedFile>
|
||||||
|
|
||||||
To list loaned books:
|
To list loaned books :
|
||||||
|
|
||||||
|
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD
|
||||||
./utils/adept_loan_mgt [-l]
|
./utils/adept_loan_mgt [-l]
|
||||||
|
|
||||||
To return a loaned book:
|
To return a loaned book :
|
||||||
|
|
||||||
|
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD
|
||||||
./utils/adept_loan_mgt -r <id>
|
./utils/adept_loan_mgt -r <id>
|
||||||
|
|
||||||
|
|
||||||
You can get utils full options description with -h or --help switch
|
You can get utils full options description with -h or --help switch
|
||||||
|
|
||||||
|
|
||||||
Binary packages
|
|
||||||
---------------
|
|
||||||
|
|
||||||
Compiled version (and AppImage) of libgourou and utils are available in [Release page](https://forge.soutade.fr/soutade/libgourou/releases)
|
|
||||||
|
|
||||||
|
|
||||||
Docker
|
Docker
|
||||||
------
|
------
|
||||||
|
|
||||||
|
|
@ -144,6 +116,7 @@ Copyright
|
||||||
Grégory Soutadé
|
Grégory Soutadé
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
License
|
License
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
|
@ -152,24 +125,9 @@ libgourou : LGPL v3 or later
|
||||||
utils : BSD
|
utils : BSD
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Special thanks
|
Special thanks
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
* _Jens_ for all test samples and utils testing
|
* _Jens_ for all test samples and utils testing
|
||||||
* _Milian_ for debug & code
|
* _Milian_ for debug & code
|
||||||
* _Berwyn H_ for all test samples, feedbacks, patches and kind donation
|
|
||||||
|
|
||||||
|
|
||||||
Donation
|
|
||||||
--------
|
|
||||||
|
|
||||||
https://www.paypal.com/donate/?hosted_button_id=JD3U6XMZCPHKN
|
|
||||||
|
|
||||||
|
|
||||||
Donators
|
|
||||||
--------
|
|
||||||
|
|
||||||
* _Berwyn H_
|
|
||||||
* _bwitt_
|
|
||||||
* _Ismail_
|
|
||||||
* _Radon_
|
|
||||||
|
|
|
||||||
133
include/Base64.h
133
include/Base64.h
|
|
@ -1,133 +0,0 @@
|
||||||
#ifndef _MACARON_BASE64_H_
|
|
||||||
#define _MACARON_BASE64_H_
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The MIT License (MIT)
|
|
||||||
* Copyright (c) 2016 tomykaira
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
* a copy of this software and associated documentation files (the
|
|
||||||
* "Software"), to deal in the Software without restriction, including
|
|
||||||
* without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
* permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
* the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be
|
|
||||||
* included in all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
||||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
namespace macaron {
|
|
||||||
|
|
||||||
class Base64 {
|
|
||||||
public:
|
|
||||||
|
|
||||||
static std::string Encode(const std::string data) {
|
|
||||||
static
|
|
||||||
#if __STDC_VERSION__ >= 201112L
|
|
||||||
constexpr
|
|
||||||
#endif /* __STDC_VERSION__ >= 201112L */
|
|
||||||
char sEncodingTable[] = {
|
|
||||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
|
||||||
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
|
||||||
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
|
|
||||||
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
|
|
||||||
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
|
||||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
|
|
||||||
'w', 'x', 'y', 'z', '0', '1', '2', '3',
|
|
||||||
'4', '5', '6', '7', '8', '9', '+', '/'
|
|
||||||
};
|
|
||||||
|
|
||||||
size_t in_len = data.size();
|
|
||||||
size_t out_len = 4 * ((in_len + 2) / 3);
|
|
||||||
std::string ret(out_len, '\0');
|
|
||||||
size_t i;
|
|
||||||
char *p = const_cast<char*>(ret.c_str());
|
|
||||||
|
|
||||||
for (i = 0; i < in_len - 2; i += 3) {
|
|
||||||
*p++ = sEncodingTable[(data[i] >> 2) & 0x3F];
|
|
||||||
*p++ = sEncodingTable[((data[i] & 0x3) << 4) | ((int) (data[i + 1] & 0xF0) >> 4)];
|
|
||||||
*p++ = sEncodingTable[((data[i + 1] & 0xF) << 2) | ((int) (data[i + 2] & 0xC0) >> 6)];
|
|
||||||
*p++ = sEncodingTable[data[i + 2] & 0x3F];
|
|
||||||
}
|
|
||||||
if (i < in_len) {
|
|
||||||
*p++ = sEncodingTable[(data[i] >> 2) & 0x3F];
|
|
||||||
if (i == (in_len - 1)) {
|
|
||||||
*p++ = sEncodingTable[((data[i] & 0x3) << 4)];
|
|
||||||
*p++ = '=';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
*p++ = sEncodingTable[((data[i] & 0x3) << 4) | ((int) (data[i + 1] & 0xF0) >> 4)];
|
|
||||||
*p++ = sEncodingTable[((data[i + 1] & 0xF) << 2)];
|
|
||||||
}
|
|
||||||
*p++ = '=';
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string Decode(const std::string& input, std::string& out) {
|
|
||||||
static
|
|
||||||
#if __STDC_VERSION__ >= 201112L
|
|
||||||
constexpr
|
|
||||||
#endif /* __STDC_VERSION__ >= 201112L */
|
|
||||||
unsigned char kDecodingTable[] = {
|
|
||||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
|
||||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
|
||||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
|
|
||||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
|
|
||||||
64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
|
||||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
|
|
||||||
64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
|
||||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
|
|
||||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
|
||||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
|
||||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
|
||||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
|
||||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
|
||||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
|
||||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
|
||||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
|
|
||||||
};
|
|
||||||
|
|
||||||
size_t in_len = input.size();
|
|
||||||
if (in_len % 4 != 0) return "Input data size is not a multiple of 4";
|
|
||||||
|
|
||||||
size_t out_len = in_len / 4 * 3;
|
|
||||||
if (input[in_len - 1] == '=') out_len--;
|
|
||||||
if (input[in_len - 2] == '=') out_len--;
|
|
||||||
|
|
||||||
out.resize(out_len);
|
|
||||||
|
|
||||||
for (size_t i = 0, j = 0; i < in_len;) {
|
|
||||||
uint32_t a = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
|
|
||||||
uint32_t b = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
|
|
||||||
uint32_t c = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
|
|
||||||
uint32_t d = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
|
|
||||||
|
|
||||||
uint32_t triple = (a << 3 * 6) + (b << 2 * 6) + (c << 1 * 6) + (d << 0 * 6);
|
|
||||||
|
|
||||||
if (j < out_len) out[j++] = (triple >> 2 * 8) & 0xFF;
|
|
||||||
if (j < out_len) out[j++] = (triple >> 1 * 8) & 0xFF;
|
|
||||||
if (j < out_len) out[j++] = (triple >> 0 * 8) & 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* _MACARON_BASE64_H_ */
|
|
||||||
|
|
@ -38,149 +38,142 @@ namespace gourou
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create an empty byte array
|
* @brief Create an empty byte array
|
||||||
*
|
*
|
||||||
* @param useMalloc If true, use malloc() instead of new[] for allocation
|
* @param useMalloc If true, use malloc() instead of new[] for allocation
|
||||||
*/
|
*/
|
||||||
ByteArray(bool useMalloc=false);
|
ByteArray(bool useMalloc=false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create an empty byte array of length bytes
|
* @brief Create an empty byte array of length bytes
|
||||||
*
|
*
|
||||||
* @param length Length of data
|
* @param length Length of data
|
||||||
* @param useMalloc If true, use malloc() instead of new[] for allocation
|
* @param useMalloc If true, use malloc() instead of new[] for allocation
|
||||||
*/
|
*/
|
||||||
ByteArray(unsigned int length, bool useMalloc=false);
|
ByteArray(unsigned int length, bool useMalloc=false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initialize ByteArray with a copy of data
|
* @brief Initialize ByteArray with a copy of data
|
||||||
*
|
*
|
||||||
* @param data Data to be copied
|
* @param data Data to be copied
|
||||||
* @param length Length of data
|
* @param length Length of data
|
||||||
*/
|
*/
|
||||||
ByteArray(const unsigned char* data, unsigned int length);
|
ByteArray(const unsigned char* data, unsigned int length);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initialize ByteArray with a copy of data
|
* @brief Initialize ByteArray with a copy of data
|
||||||
*
|
*
|
||||||
* @param data Data to be copied
|
* @param data Data to be copied
|
||||||
* @param length Optional length of data. If length == -1, it use strlen(data) as length
|
* @param length Optional length of data. If length == -1, it use strlen(data) as length
|
||||||
*/
|
*/
|
||||||
ByteArray(const char* data, int length=-1);
|
ByteArray(const char* data, int length=-1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initialize ByteArray with a copy of str
|
* @brief Initialize ByteArray with a copy of str
|
||||||
*
|
*
|
||||||
* @param str Use internal data of str
|
* @param str Use internal data of str
|
||||||
*/
|
*/
|
||||||
ByteArray(const std::string& str);
|
ByteArray(const std::string& str);
|
||||||
|
|
||||||
ByteArray(const ByteArray& other);
|
ByteArray(const ByteArray& other);
|
||||||
~ByteArray();
|
~ByteArray();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Encode "other" data into base64 and put it into a ByteArray
|
* @brief Encode "other" data into base64 and put it into a ByteArray
|
||||||
*/
|
*/
|
||||||
static ByteArray fromBase64(const ByteArray& other);
|
static ByteArray fromBase64(const ByteArray& other);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Encode data into base64 and put it into a ByteArray
|
* @brief Encode data into base64 and put it into a ByteArray
|
||||||
*
|
*
|
||||||
* @param data Data to be encoded
|
* @param data Data to be encoded
|
||||||
* @param length Optional length of data. If length == -1, it use strlen(data) as length
|
* @param length Optional length of data. If length == -1, it use strlen(data) as length
|
||||||
*/
|
*/
|
||||||
static ByteArray fromBase64(const char* data, int length=-1);
|
static ByteArray fromBase64(const char* data, int length=-1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Encode str into base64 and put it into a ByteArray
|
* @brief Encode str into base64 and put it into a ByteArray
|
||||||
*
|
*
|
||||||
* @param str Use internal data of str
|
* @param str Use internal data of str
|
||||||
*/
|
*/
|
||||||
static ByteArray fromBase64(const std::string& str);
|
static ByteArray fromBase64(const std::string& str);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return a string with base64 encoded internal data
|
* @brief Return a string with base64 encoded internal data
|
||||||
*/
|
*/
|
||||||
std::string toBase64();
|
std::string toBase64();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Convert hex string into bytes
|
* @brief Return a string with human readable hex encoded internal data
|
||||||
*
|
*/
|
||||||
* @param str Hex string
|
std::string toHex();
|
||||||
*/
|
|
||||||
static ByteArray fromHex(const std::string& str);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return a string with human readable hex encoded internal data
|
* @brief Append a byte to internal data
|
||||||
*/
|
*/
|
||||||
std::string toHex();
|
void append(unsigned char c);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Append a byte to internal data
|
* @brief Append data to internal data
|
||||||
*/
|
*/
|
||||||
void append(unsigned char c);
|
void append(const unsigned char* data, unsigned int length);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Append data to internal data
|
* @brief Append str to internal data
|
||||||
*/
|
*/
|
||||||
void append(const unsigned char* data, unsigned int length);
|
void append(const char* str);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Append str to internal data
|
* @brief Append str to internal data
|
||||||
*/
|
*/
|
||||||
void append(const char* str);
|
void append(const std::string& str);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Append str to internal data
|
* @brief Get internal data. Must bot be freed
|
||||||
*/
|
*/
|
||||||
void append(const std::string& str);
|
unsigned char* data() {return _data;}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get internal data. Must not be freed
|
* @brief Get internal data and increment internal reference counter.
|
||||||
*/
|
* Must bot be freed
|
||||||
unsigned char* data() {return _data;}
|
*/
|
||||||
|
unsigned char* takeShadowData() {addRef() ; return _data;}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get internal data and increment internal reference counter.
|
* @brief Release shadow data. It can now be freed by ByteArray
|
||||||
* Must bot be freed
|
*/
|
||||||
*/
|
void releaseShadowData() {delRef();}
|
||||||
unsigned char* takeShadowData() {addRef() ; return _data;}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Release shadow data. It can now be freed by ByteArray
|
* @brief Get internal data length
|
||||||
*/
|
*/
|
||||||
void releaseShadowData() {delRef();}
|
unsigned int length() const {return _length;}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get internal data length
|
* @brief Get internal data length
|
||||||
*/
|
*/
|
||||||
unsigned int length() const {return _length;}
|
unsigned int size() const {return length();}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get internal data length
|
* @brief Increase or decrease internal buffer
|
||||||
*/
|
* @param length New length of internal buffer
|
||||||
unsigned int size() const {return length();}
|
* @param keepData If true copy old data on new buffer, if false,
|
||||||
|
* create a new buffer with random data
|
||||||
/**
|
*/
|
||||||
* @brief Increase or decrease internal buffer
|
void resize(unsigned int length, bool keepData=true);
|
||||||
* @param length New length of internal buffer
|
|
||||||
* @param keepData If true copy old data on new buffer, if false,
|
|
||||||
* create a new buffer with random data
|
|
||||||
*/
|
|
||||||
void resize(unsigned int length, bool keepData=true);
|
|
||||||
|
|
||||||
ByteArray& operator=(const ByteArray& other);
|
|
||||||
|
|
||||||
|
ByteArray& operator=(const ByteArray& other);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void initData(const unsigned char* data, unsigned int length);
|
void initData(const unsigned char* data, unsigned int length);
|
||||||
void addRef();
|
void addRef();
|
||||||
void delRef();
|
void delRef();
|
||||||
|
|
||||||
bool _useMalloc;
|
bool _useMalloc;
|
||||||
unsigned char* _data;
|
unsigned char* _data;
|
||||||
unsigned int _length;
|
unsigned int _length;
|
||||||
static std::map<unsigned char*, int> refCounter;
|
static std::map<unsigned char*, int> refCounter;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -30,54 +30,54 @@ namespace gourou
|
||||||
class Device
|
class Device
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static const int DEVICE_KEY_SIZE = 16;
|
static const int DEVICE_KEY_SIZE = 16;
|
||||||
static const int DEVICE_SERIAL_LEN = 10;
|
static const int DEVICE_SERIAL_LEN = 10;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Main Device constructor
|
* @brief Main Device constructor
|
||||||
*
|
*
|
||||||
* @param processor Instance of DRMProcessor
|
* @param processor Instance of DRMProcessor
|
||||||
* @param deviceFile Path of device.xml
|
* @param deviceFile Path of device.xml
|
||||||
* @param deviceKeyFile Path of devicesalt
|
* @param deviceKeyFile Path of devicesalt
|
||||||
*/
|
*/
|
||||||
Device(DRMProcessor* processor, const std::string& deviceFile, const std::string& deviceKeyFile);
|
Device(DRMProcessor* processor, const std::string& deviceFile, const std::string& deviceKeyFile);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return value of devicesalt file (DEVICE_KEY_SIZE len)
|
* @brief Return value of devicesalt file (DEVICE_KEY_SIZE len)
|
||||||
*/
|
*/
|
||||||
const unsigned char* getDeviceKey();
|
const unsigned char* getDeviceKey();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get one value of device.xml (deviceClass, deviceSerial, deviceName, deviceType, hobbes, clientOS, clientLocale)
|
* @brief Get one value of device.xml (deviceClass, deviceSerial, deviceName, deviceType, hobbes, clientOS, clientLocale)
|
||||||
*/
|
*/
|
||||||
std::string getProperty(const std::string& property, const std::string& _default=std::string(""));
|
std::string getProperty(const std::string& property, const std::string& _default=std::string(""));
|
||||||
std::string operator[](const std::string& property);
|
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);
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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:
|
private:
|
||||||
DRMProcessor* processor;
|
DRMProcessor* processor;
|
||||||
std::string deviceFile;
|
std::string deviceFile;
|
||||||
std::string deviceKeyFile;
|
std::string deviceKeyFile;
|
||||||
unsigned char deviceKey[DEVICE_KEY_SIZE];
|
unsigned char deviceKey[DEVICE_KEY_SIZE];
|
||||||
std::map<std::string, std::string> properties;
|
std::map<std::string, std::string> properties;
|
||||||
|
|
||||||
Device(DRMProcessor* processor);
|
Device(DRMProcessor* processor);
|
||||||
|
|
||||||
std::string makeFingerprint(const std::string& serial);
|
std::string makeFingerprint(const std::string& serial);
|
||||||
std::string makeSerial(bool random);
|
std::string makeSerial(bool random);
|
||||||
void parseDeviceFile();
|
void parseDeviceFile();
|
||||||
void parseDeviceKeyFile();
|
void parseDeviceKeyFile();
|
||||||
void createDeviceFile(const std::string& hobbes, bool randomSerial);
|
void createDeviceFile(const std::string& hobbes, bool randomSerial);
|
||||||
void createDeviceKeyFile();
|
void createDeviceKeyFile();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,376 +34,381 @@ namespace gourou
|
||||||
class DigestInterface
|
class DigestInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Create a digest handler
|
* @brief Create a digest handler
|
||||||
*
|
*
|
||||||
* @param digestName Digest name to instanciate
|
* @param digestName Digest name to instanciate
|
||||||
*/
|
*/
|
||||||
virtual void* createDigest(const std::string& digestName) = 0;
|
virtual void* createDigest(const std::string& digestName) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Update digest engine with new data
|
* @brief Update digest engine with new data
|
||||||
*
|
*
|
||||||
* @param handler Digest handler
|
* @param handler Digest handler
|
||||||
* @param data Data to digest
|
* @param data Data to digest
|
||||||
* @param length Length of data
|
* @param length Length of data
|
||||||
*/
|
*
|
||||||
virtual void digestUpdate(void* handler, unsigned char* data, unsigned int length) = 0;
|
* @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
|
* @brief Finalize digest with remained buffered data and destroy handler
|
||||||
*
|
*
|
||||||
* @param handler Digest handler
|
* @param handler Digest handler
|
||||||
* @param digestOut Digest result (buffer must be pre allocated with right size)
|
* @param digestOut Digest result (buffer must be pre allocated with right size)
|
||||||
*/
|
*
|
||||||
virtual void digestFinalize(void* handler, unsigned char* digestOut) = 0;
|
* @return OK/KO
|
||||||
|
*/
|
||||||
|
virtual int digestFinalize(void* handler, unsigned char* digestOut) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Global digest function
|
* @brief Global digest function
|
||||||
*
|
*
|
||||||
* @param digestName Digest name to instanciate
|
* @param digestName Digest name to instanciate
|
||||||
* @param data Data to digest
|
* @param data Data to digest
|
||||||
* @param length Length of data
|
* @param length Length of data
|
||||||
* @param digestOut Digest result (buffer must be pre allocated with right size)
|
* @param digestOut Digest result (buffer must be pre allocated with right size)
|
||||||
*/
|
*
|
||||||
virtual void digest(const std::string& digestName, unsigned char* data, unsigned int length, unsigned char* digestOut) = 0;
|
* @return OK/KO
|
||||||
|
*/
|
||||||
|
virtual int digest(const std::string& digestName, unsigned char* data, unsigned int length, unsigned char* digestOut) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RandomInterface
|
class RandomInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Generate random bytes
|
* @brief Generate random bytes
|
||||||
*
|
*
|
||||||
* @param bytesOut Buffer to fill with random bytes
|
* @param bytesOut Buffer to fill with random bytes
|
||||||
* @param length Length of bytesOut
|
* @param length Length of bytesOut
|
||||||
*/
|
*/
|
||||||
virtual void randBytes(unsigned char* bytesOut, unsigned int length) = 0;
|
virtual void randBytes(unsigned char* bytesOut, unsigned int length) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class HTTPInterface
|
class HTTPInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Send HTTP (GET or POST) request
|
* @brief Send HTTP (GET or POST) request
|
||||||
*
|
*
|
||||||
* @param URL HTTP URL
|
* @param URL HTTP URL
|
||||||
* @param POSTData POST data if needed, if not set, a GET request is done
|
* @param POSTData POST data if needed, if not set, a GET request is done
|
||||||
* @param contentType Optional content type of POST Data
|
* @param contentType Optional content type of POST Data
|
||||||
* @param responseHeaders Optional Response headers of HTTP request
|
* @param responseHeaders Optional Response headers of HTTP request
|
||||||
* @param fd Optional file descriptor to write request result
|
* @param fd Optional file descriptor to write request result
|
||||||
* @param resume false if target file should be truncated, true to try resume download (works only in combination with a valid fd)
|
* @param resume false if target file should be truncated, true to try resume download (works only in combination with a valid fd)
|
||||||
*
|
*
|
||||||
* @return data of HTTP response
|
* @return data of HTTP response
|
||||||
*/
|
*/
|
||||||
virtual std::string sendHTTPRequest(const std::string& URL, const std::string& POSTData=std::string(""), const std::string& contentType=std::string(""), std::map<std::string, std::string>* responseHeaders=0, int fd=0, bool resume=false) = 0;
|
virtual std::string sendHTTPRequest(const std::string& URL, const std::string& POSTData=std::string(""), const std::string& contentType=std::string(""), std::map<std::string, std::string>* responseHeaders=0, int fd=0, bool resume=false) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RSAInterface
|
class RSAInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum RSA_KEY_TYPE {
|
enum RSA_KEY_TYPE {
|
||||||
RSA_KEY_PKCS12 = 0,
|
RSA_KEY_PKCS12 = 0,
|
||||||
RSA_KEY_PKCS8,
|
RSA_KEY_X509
|
||||||
RSA_KEY_X509
|
};
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Encrypt data with RSA private key. Data is padded using PKCS1.5
|
* @brief Encrypt data with RSA private key. Data is padded using PKCS1.5
|
||||||
*
|
*
|
||||||
* @param RSAKey RSA key in binary form
|
* @param RSAKey RSA key in binary form
|
||||||
* @param RSAKeyLength RSA key length
|
* @param RSAKeyLength RSA key length
|
||||||
* @param keyType Key type
|
* @param keyType Key type
|
||||||
* @param password Optional password for RSA PKCS12 certificate
|
* @param password Optional password for RSA PKCS12 certificate
|
||||||
* @param data Data to encrypt
|
* @param data Data to encrypt
|
||||||
* @param dataLength Data length
|
* @param dataLength Data length
|
||||||
* @param res Encryption result (pre allocated buffer)
|
* @param res Encryption result (pre allocated buffer)
|
||||||
*/
|
*/
|
||||||
virtual void RSAPrivateEncrypt(const unsigned char* RSAKey, unsigned int RSAKeyLength,
|
virtual void RSAPrivateEncrypt(const unsigned char* RSAKey, unsigned int RSAKeyLength,
|
||||||
const RSA_KEY_TYPE keyType, const std::string& password,
|
const RSA_KEY_TYPE keyType, const std::string& password,
|
||||||
const unsigned char* data, unsigned dataLength,
|
const unsigned char* data, unsigned dataLength,
|
||||||
unsigned char* res) = 0;
|
unsigned char* res) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Decrypt 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 RSAPrivateDecrypt(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 Decrypt data with RSA private key. Data is padded using PKCS1.5
|
* @brief Encrypt data with RSA public key. Data is padded using PKCS1.5
|
||||||
*
|
*
|
||||||
* @param RSAKey RSA key in binary form
|
* @param RSAKey RSA key in binary form
|
||||||
* @param RSAKeyLength RSA key length
|
* @param RSAKeyLength RSA key length
|
||||||
* @param keyType Key type
|
* @param keyType Key type
|
||||||
* @param password Optional password for RSA PKCS12 certificate
|
* @param password Optional password for RSA PKCS12 certificate
|
||||||
* @param data Data to encrypt
|
* @param data Data to encrypt
|
||||||
* @param dataLength Data length
|
* @param dataLength Data length
|
||||||
* @param res Encryption result (pre allocated buffer)
|
* @param res Encryption result (pre allocated buffer)
|
||||||
*/
|
*/
|
||||||
virtual void RSAPrivateDecrypt(const unsigned char* RSAKey, unsigned int RSAKeyLength,
|
virtual void RSAPublicEncrypt(const unsigned char* RSAKey, unsigned int RSAKeyLength,
|
||||||
const RSA_KEY_TYPE keyType, const std::string& password,
|
const RSA_KEY_TYPE keyType,
|
||||||
const unsigned char* data, unsigned dataLength,
|
const unsigned char* data, unsigned dataLength,
|
||||||
unsigned char* res) = 0;
|
unsigned char* res) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Encrypt data with RSA public key. Data is padded using PKCS1.5
|
* @brief Generate RSA key. Expnonent is fixed (65537 / 0x10001)
|
||||||
*
|
*
|
||||||
* @param RSAKey RSA key in binary form
|
* @param keyLengthBits Length of key (in bits) to generate
|
||||||
* @param RSAKeyLength RSA key length
|
*
|
||||||
* @param keyType Key type
|
* @return generatedKey
|
||||||
* @param password Optional password for RSA PKCS12 certificate
|
*/
|
||||||
* @param data Data to encrypt
|
virtual void* generateRSAKey(int keyLengthBits) = 0;
|
||||||
* @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)
|
* @brief Destroy key previously generated
|
||||||
*
|
*
|
||||||
* @param keyLengthBits Length of key (in bits) to generate
|
* @param handler Key to destroy
|
||||||
*
|
*/
|
||||||
* @return generatedKey
|
virtual void destroyRSAHandler(void* handler) = 0;
|
||||||
*/
|
|
||||||
virtual void* generateRSAKey(int keyLengthBits) = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Destroy key previously generated
|
* @brief Extract public key (big number) from RSA handler
|
||||||
*
|
*
|
||||||
* @param handler Key to destroy
|
* @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)
|
||||||
virtual void destroyRSAHandler(void* handler) = 0;
|
* @param keyOutLength Length of result
|
||||||
|
*/
|
||||||
|
virtual void extractRSAPublicKey(void* handler, unsigned char** keyOut, unsigned int* keyOutLength) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Extract public key (big number) from RSA handler
|
* @brief Extract private key (big number) from RSA handler
|
||||||
*
|
*
|
||||||
* @param handler RSA handler (generated key)
|
* @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 keyOut Pre allocated buffer (if *keyOut != 0). If *keyOut is 0, memory is internally allocated (must be freed)
|
||||||
* @param keyOutLength Length of result
|
* @param keyOutLength Length of result
|
||||||
*/
|
*/
|
||||||
virtual void extractRSAPublicKey(void* handler, unsigned char** keyOut, unsigned int* keyOutLength) = 0;
|
virtual void extractRSAPrivateKey(void* handler, unsigned char** keyOut, unsigned int* keyOutLength) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Extract private key (big number) from RSA handler
|
* @brief Extract certificate from PKCS12 blob
|
||||||
*
|
*
|
||||||
* @param handler RSA handler (generated key)
|
* @param RSAKey RSA key in binary form
|
||||||
* @param keyOut Pre allocated buffer (if *keyOut != 0). If *keyOut is 0, memory is internally allocated (must be freed)
|
* @param RSAKeyLength RSA key length
|
||||||
* @param keyOutLength Length of result
|
* @param keyType Key type
|
||||||
*/
|
* @param password Optional password for RSA PKCS12 certificate
|
||||||
virtual void extractRSAPrivateKey(void* handler, unsigned char** keyOut, unsigned int* keyOutLength) = 0;
|
* @param certOut Result certificate
|
||||||
|
* @param certOutLength Result certificate length
|
||||||
/**
|
*/
|
||||||
* @brief Extract certificate from PKCS12 blob
|
virtual void extractCertificate(const unsigned char* RSAKey, unsigned int RSAKeyLength,
|
||||||
*
|
const RSA_KEY_TYPE keyType, const std::string& password,
|
||||||
* @param RSAKey RSA key in binary form
|
unsigned char** certOut, unsigned int* certOutLength) = 0;
|
||||||
* @param RSAKeyLength RSA key length
|
|
||||||
* @param keyType Key type
|
|
||||||
* @param password Optional password for RSA PKCS12 certificate
|
|
||||||
* @param certOut Result certificate
|
|
||||||
* @param certOutLength Result certificate length
|
|
||||||
*/
|
|
||||||
virtual void extractCertificate(const unsigned char* RSAKey, unsigned int RSAKeyLength,
|
|
||||||
const RSA_KEY_TYPE keyType, const std::string& password,
|
|
||||||
unsigned char** certOut, unsigned int* certOutLength) = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CryptoInterface
|
class CryptoInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum CRYPTO_ALGO {
|
enum CRYPTO_ALGO {
|
||||||
ALGO_AES=0,
|
ALGO_AES=0,
|
||||||
ALGO_RC4
|
ALGO_RC4
|
||||||
};
|
};
|
||||||
|
|
||||||
enum CHAINING_MODE {
|
enum CHAINING_MODE {
|
||||||
CHAIN_ECB=0,
|
CHAIN_ECB=0,
|
||||||
CHAIN_CBC
|
CHAIN_CBC
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Do encryption. If length of data is not multiple of block size, PKCS#5 padding is done
|
||||||
|
*
|
||||||
|
* @param algo Algorithm to use
|
||||||
|
* @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 Encrypt(CRYPTO_ALGO algo, 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 Do encryption. If length of data is not multiple of block size, PKCS#5 padding is done
|
* @brief Init encryption
|
||||||
*
|
*
|
||||||
* @param algo Algorithm to use
|
* @param chaining Chaining mode
|
||||||
* @param chaining Chaining mode
|
* @param key Key
|
||||||
* @param key AES key
|
* @param keyLength Key length
|
||||||
* @param keyLength AES key length
|
* @param iv Optional IV key
|
||||||
* @param iv IV key
|
* @param ivLength Optional IV key length
|
||||||
* @param ivLength IV key length
|
*
|
||||||
* @param dataIn Data to encrypt
|
* @return AES handler
|
||||||
* @param dataInLength Data length
|
*/
|
||||||
* @param dataOut Encrypted data
|
virtual void* EncryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
||||||
* @param dataOutLength Length of encrypted data
|
const unsigned char* key, unsigned int keyLength,
|
||||||
*/
|
const unsigned char* iv=0, unsigned int ivLength=0) = 0;
|
||||||
virtual void encrypt(CRYPTO_ALGO algo, 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 encryption
|
* @brief Encrypt data
|
||||||
*
|
*
|
||||||
* @param chaining Chaining mode
|
* @param handler Crypto handler
|
||||||
* @param key Key
|
* @param dataIn Data to encrypt
|
||||||
* @param keyLength Key length
|
* @param dataInLength Data length
|
||||||
* @param iv Optional IV key
|
* @param dataOut Encrypted data
|
||||||
* @param ivLength Optional IV key length
|
* @param dataOutLength Length of encrypted data
|
||||||
*
|
*/
|
||||||
* @return AES handler
|
virtual void EncryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
|
||||||
*/
|
unsigned char* dataOut, unsigned int* dataOutLength) = 0;
|
||||||
virtual void* encryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
|
||||||
const unsigned char* key, unsigned int keyLength,
|
|
||||||
const unsigned char* iv=0, unsigned int ivLength=0) = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Encrypt data
|
* @brief Finalizeencryption (pad and encrypt last block if needed)
|
||||||
*
|
* Destroy handler at the end
|
||||||
* @param handler Crypto handler
|
*
|
||||||
* @param dataIn Data to encrypt
|
* @param handler Crypto handler
|
||||||
* @param dataInLength Data length
|
* @param dataOut Last block of encrypted data
|
||||||
* @param dataOut Encrypted data
|
* @param dataOutLength Length of encrypted data
|
||||||
* @param dataOutLength Length of encrypted data
|
*/
|
||||||
*/
|
virtual void EncryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength) = 0;
|
||||||
virtual void encryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
|
|
||||||
unsigned char* dataOut, unsigned int* dataOutLength) = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Finalize encryption (pad and encrypt last block if needed)
|
* @brief Do decryption. If length of data is not multiple of block size, PKCS#5 padding is done
|
||||||
* Destroy handler at the end
|
*
|
||||||
*
|
* @param algo Algorithm to use
|
||||||
* @param handler Crypto handler
|
* @param chaining Chaining mode
|
||||||
* @param dataOut Last block of encrypted data
|
* @param key AES key
|
||||||
* @param dataOutLength Length of encrypted data
|
* @param keyLength AES key length
|
||||||
*/
|
* @param iv IV key
|
||||||
virtual void encryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength) = 0;
|
* @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 Decrypt(CRYPTO_ALGO algo, 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 Do decryption. If length of data is not multiple of block size, PKCS#5 padding is done
|
* @brief Init decryption
|
||||||
*
|
*
|
||||||
* @param algo Algorithm to use
|
* @param chaining Chaining mode
|
||||||
* @param chaining Chaining mode
|
* @param key Key
|
||||||
* @param key AES key
|
* @param keyLength Key length
|
||||||
* @param keyLength AES key length
|
* @param iv IV key
|
||||||
* @param iv IV key
|
* @param ivLength IV key length
|
||||||
* @param ivLength IV key length
|
*
|
||||||
* @param dataIn Data to encrypt
|
* @return AES handler
|
||||||
* @param dataInLength Data length
|
*/
|
||||||
* @param dataOut Encrypted data
|
virtual void* DecryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
||||||
* @param dataOutLength Length of encrypted data
|
const unsigned char* key, unsigned int keyLength,
|
||||||
*/
|
const unsigned char* iv=0, unsigned int ivLength=0) = 0;
|
||||||
virtual void decrypt(CRYPTO_ALGO algo, 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 decryption
|
* @brief Decrypt data
|
||||||
*
|
*
|
||||||
* @param chaining Chaining mode
|
* @param handler Crypto handler
|
||||||
* @param key Key
|
* @param dataIn Data to decrypt
|
||||||
* @param keyLength Key length
|
* @param dataInLength Data length
|
||||||
* @param iv IV key
|
* @param dataOut Decrypted data
|
||||||
* @param ivLength IV key length
|
* @param dataOutLength Length of decrypted data
|
||||||
*
|
*/
|
||||||
* @return AES handler
|
virtual void DecryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
|
||||||
*/
|
unsigned char* dataOut, unsigned int* dataOutLength) = 0;
|
||||||
virtual void* decryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
/**
|
||||||
const unsigned char* key, unsigned int keyLength,
|
* @brief Finalize decryption (decrypt last block and remove padding if it is set).
|
||||||
const unsigned char* iv=0, unsigned int ivLength=0) = 0;
|
* Destroy handler at the end
|
||||||
|
*
|
||||||
/**
|
* @param handler Crypto handler
|
||||||
* @brief Decrypt data
|
* @param dataOut Last block decrypted data
|
||||||
*
|
* @param dataOutLength Length of decrypted data
|
||||||
* @param handler Crypto handler
|
*/
|
||||||
* @param dataIn Data to decrypt
|
virtual void DecryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength) = 0;
|
||||||
* @param dataInLength Data length
|
|
||||||
* @param dataOut Decrypted data
|
|
||||||
* @param dataOutLength Length of decrypted data
|
|
||||||
*/
|
|
||||||
virtual void decryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
|
|
||||||
unsigned char* dataOut, unsigned int* dataOutLength) = 0;
|
|
||||||
/**
|
|
||||||
* @brief Finalize decryption (decrypt last block and remove padding if it is set).
|
|
||||||
* Destroy handler at the end
|
|
||||||
*
|
|
||||||
* @param handler Crypto handler
|
|
||||||
* @param dataOut Last block decrypted data
|
|
||||||
* @param dataOutLength Length of decrypted data
|
|
||||||
*/
|
|
||||||
virtual void decryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength) = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class ZIPInterface
|
class ZIPInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Open a zip file and return an handler
|
* @brief Open a zip file and return an handler
|
||||||
*
|
*
|
||||||
* @param path Path of zip file
|
* @param path Path of zip file
|
||||||
*
|
*
|
||||||
* @return ZIP file handler
|
* @return ZIP file handler
|
||||||
*/
|
*/
|
||||||
virtual void* zipOpen(const std::string& path) = 0;
|
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
|
||||||
|
* @param result Result buffer
|
||||||
|
* @param decompress If false, don't decompress read data
|
||||||
|
*/
|
||||||
|
virtual void zipReadFile(void* handler, const std::string& path, ByteArray& result, bool decompress=true) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write zip internal file
|
||||||
|
*
|
||||||
|
* @param handler ZIP file handler
|
||||||
|
* @param path Internal path inside zip file
|
||||||
|
* @param content File content
|
||||||
|
*/
|
||||||
|
virtual void zipWriteFile(void* handler, const std::string& path, ByteArray& content) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read zip internal file
|
* @brief Delete zip internal file
|
||||||
*
|
*
|
||||||
* @param handler ZIP file handler
|
* @param handler ZIP file handler
|
||||||
* @param path Internal path inside zip file
|
* @param path Internal path inside zip file
|
||||||
* @param result Result buffer
|
*/
|
||||||
* @param decompress If false, don't decompress read data
|
virtual void zipDeleteFile(void* handler, const std::string& path) = 0;
|
||||||
*/
|
|
||||||
virtual void zipReadFile(void* handler, const std::string& path, ByteArray& result, bool decompress=true) = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Write zip internal file
|
* @brief Close ZIP file handler
|
||||||
*
|
*
|
||||||
* @param handler ZIP file handler
|
* @param handler ZIP file handler
|
||||||
* @param path Internal path inside zip file
|
*/
|
||||||
* @param content File content
|
virtual void zipClose(void* handler) = 0;
|
||||||
*/
|
|
||||||
virtual void zipWriteFile(void* handler, const std::string& path, ByteArray& content) = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Delete zip internal file
|
* @brief Inflate algorithm
|
||||||
*
|
*
|
||||||
* @param handler ZIP file handler
|
* @param data Data to inflate
|
||||||
* @param path Internal path inside zip file
|
* @param result Zipped data
|
||||||
*/
|
* @param wbits Window bits value for libz
|
||||||
virtual void zipDeleteFile(void* handler, const std::string& path) = 0;
|
*/
|
||||||
|
virtual void inflate(gourou::ByteArray& data, gourou::ByteArray& result,
|
||||||
/**
|
int wbits=-15) = 0;
|
||||||
* @brief Close ZIP file handler
|
|
||||||
*
|
/**
|
||||||
* @param handler ZIP file handler
|
* @brief Deflate algorithm
|
||||||
*/
|
*
|
||||||
virtual void zipClose(void* handler) = 0;
|
* @param data Data to deflate
|
||||||
|
* @param result Unzipped data
|
||||||
/**
|
* @param wbits Window bits value for libz
|
||||||
* @brief Inflate algorithm
|
* @param compressionLevel Compression level for libz
|
||||||
*
|
*/
|
||||||
* @param data Data to inflate
|
virtual void deflate(gourou::ByteArray& data, gourou::ByteArray& result,
|
||||||
* @param result Zipped data
|
int wbits=-15, int compressionLevel=8) = 0;
|
||||||
* @param wbits Window bits value for libz
|
|
||||||
*/
|
|
||||||
virtual void inflate(gourou::ByteArray& data, gourou::ByteArray& result,
|
|
||||||
int wbits=-15) = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Deflate algorithm
|
|
||||||
*
|
|
||||||
* @param data Data to deflate
|
|
||||||
* @param result Unzipped data
|
|
||||||
* @param wbits Window bits value for libz
|
|
||||||
* @param compressionLevel Compression level for libz
|
|
||||||
*/
|
|
||||||
virtual void deflate(gourou::ByteArray& data, gourou::ByteArray& result,
|
|
||||||
int wbits=-15, int compressionLevel=8) = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DRMProcessorClient: public DigestInterface, public RandomInterface, public HTTPInterface, \
|
class DRMProcessorClient: public DigestInterface, public RandomInterface, public HTTPInterface, \
|
||||||
public RSAInterface, public CryptoInterface, public ZIPInterface
|
public RSAInterface, public CryptoInterface, public ZIPInterface
|
||||||
{};
|
{};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -34,52 +34,52 @@ namespace gourou
|
||||||
class FulfillmentItem
|
class FulfillmentItem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Main constructor. Not to be called by user
|
* @brief Main constructor. Not to be called by user
|
||||||
*
|
*
|
||||||
* @param doc Fulfill reply
|
* @param doc Fulfill reply
|
||||||
* @param user User pointer
|
* @param user User pointer
|
||||||
*/
|
*/
|
||||||
FulfillmentItem(pugi::xml_document& doc, User* user);
|
FulfillmentItem(pugi::xml_document& doc, User* user);
|
||||||
|
|
||||||
~FulfillmentItem();
|
~FulfillmentItem();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return metadata value from ACSM metadata section
|
* @brief Return metadata value from ACSM metadata section
|
||||||
*
|
*
|
||||||
* @param name Name of key to return
|
* @param name Name of key to return
|
||||||
*/
|
*/
|
||||||
std::string getMetadata(std::string name);
|
std::string getMetadata(std::string name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return rights generated by ACS server (XML format)
|
* @brief Return rights generated by ACS server (XML format)
|
||||||
*/
|
*/
|
||||||
std::string getRights();
|
std::string getRights();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return epub download URL
|
* @brief Return epub download URL
|
||||||
*/
|
*/
|
||||||
std::string getDownloadURL();
|
std::string getDownloadURL();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return resource value
|
* @brief Return resource value
|
||||||
*/
|
*/
|
||||||
std::string getResource();
|
std::string getResource();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return loan token if there is one
|
* @brief Return loan token if there is one
|
||||||
*/
|
*/
|
||||||
LoanToken* getLoanToken();
|
LoanToken* getLoanToken();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
pugi::xml_document fulfillDoc;
|
pugi::xml_document fulfillDoc;
|
||||||
pugi::xml_node metadatas;
|
pugi::xml_node metadatas;
|
||||||
pugi::xml_document rights;
|
pugi::xml_document rights;
|
||||||
std::string downloadURL;
|
std::string downloadURL;
|
||||||
std::string resource;
|
std::string resource;
|
||||||
LoanToken* loanToken;
|
LoanToken* loanToken;
|
||||||
|
|
||||||
void buildRights(const pugi::xml_node& licenseToken, User* user);
|
void buildRights(const pugi::xml_node& licenseToken, User* user);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,17 +27,20 @@
|
||||||
#include "drmprocessorclient.h"
|
#include "drmprocessorclient.h"
|
||||||
|
|
||||||
#include <pugixml.hpp>
|
#include <pugixml.hpp>
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#ifndef HOBBES_DEFAULT_VERSION
|
#ifndef HOBBES_DEFAULT_VERSION
|
||||||
#define HOBBES_DEFAULT_VERSION "10.0.4"
|
#define HOBBES_DEFAULT_VERSION "10.0.4"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef DEFAULT_ADEPT_DIR
|
||||||
|
#define DEFAULT_ADEPT_DIR "./.adept"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef ACS_SERVER
|
#ifndef ACS_SERVER
|
||||||
#define ACS_SERVER "http://adeactivate.adobe.com/adept"
|
#define ACS_SERVER "http://adeactivate.adobe.com/adept"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define LIBGOUROU_VERSION "0.8.8"
|
#define LIBGOUROU_VERSION "0.7.2"
|
||||||
|
|
||||||
namespace gourou
|
namespace gourou
|
||||||
{
|
{
|
||||||
|
|
@ -48,204 +51,193 @@ namespace gourou
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static const std::string VERSION;
|
static const std::string VERSION;
|
||||||
|
|
||||||
enum ITEM_TYPE { EPUB=0, PDF };
|
enum ITEM_TYPE { EPUB=0, PDF };
|
||||||
/**
|
/**
|
||||||
* @brief Main constructor. To be used once all is configured (user has signedIn, device is activated)
|
* @brief Main constructor. To be used once all is configured (user has signedIn, device is activated)
|
||||||
*
|
*
|
||||||
* @param client Client processor
|
* @param client Client processor
|
||||||
* @param deviceFile Path of device.xml
|
* @param deviceFile Path of device.xml
|
||||||
* @param activationFile Path of activation.xml
|
* @param activationFile Path of activation.xml
|
||||||
* @param deviceKeyFile Path of devicesalt
|
* @param deviceKeyFile Path of devicesalt
|
||||||
*/
|
*/
|
||||||
DRMProcessor(DRMProcessorClient* client, const std::string& deviceFile, const std::string& activationFile, const std::string& deviceKeyFile);
|
DRMProcessor(DRMProcessorClient* client, const std::string& deviceFile, const std::string& activationFile, const std::string& deviceKeyFile);
|
||||||
|
|
||||||
|
~DRMProcessor();
|
||||||
|
|
||||||
~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 Fulfill ACSM file to server in order to retrieve ePub fulfillment item
|
* @brief Once fulfilled, ePub file needs to be downloaded.
|
||||||
*
|
* During this operation, DRM information is added into downloaded file
|
||||||
* @param ACSMFile Path of ACSMFile
|
*
|
||||||
* @param notify Notify server if requested by response
|
* @param item Item from fulfill() method
|
||||||
*
|
* @param path Output file path
|
||||||
* @return a FulfillmentItem if all is OK
|
* @param resume false if target file should be truncated, true to try resume download
|
||||||
*/
|
*
|
||||||
FulfillmentItem* fulfill(const std::string& ACSMFile, bool notify=true);
|
* @return Type of downloaded item
|
||||||
|
*/
|
||||||
|
ITEM_TYPE download(FulfillmentItem* item, std::string path, bool resume=false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Once fulfilled, ePub file needs to be downloaded.
|
* @brief SignIn into ACS Server (required to activate device)
|
||||||
* During this operation, DRM information is added into downloaded file
|
*
|
||||||
*
|
* @param adobeID AdobeID username
|
||||||
* @param item Item from fulfill() method
|
* @param adobePassword Adobe password
|
||||||
* @param path Output file path
|
*/
|
||||||
* @param resume false if target file should be truncated, true to try resume download
|
void signIn(const std::string& adobeID, const std::string& adobePassword);
|
||||||
*
|
|
||||||
* @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)
|
* @brief Activate newly created device (user must have successfuly signedIn before)
|
||||||
*
|
*/
|
||||||
* @param adobeID AdobeID username
|
void activateDevice();
|
||||||
* @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)
|
* @brief Return loaned book to server
|
||||||
*/
|
*
|
||||||
void activateDevice();
|
* @param loanID Loan ID received during fulfill
|
||||||
|
* @param operatorURL URL of operator that loans this book
|
||||||
/**
|
*/
|
||||||
* @brief Return loaned book to server
|
void returnLoan(const std::string& loanID, const std::string& operatorURL);
|
||||||
*
|
|
||||||
* @param loanID Loan ID received during fulfill
|
/**
|
||||||
* @param operatorURL URL of operator that loans this book
|
* @brief Create a new ADEPT environment (device.xml, devicesalt and activation.xml).
|
||||||
* @param notify Notify server if requested by response
|
*
|
||||||
*/
|
* @param client Client processor
|
||||||
void returnLoan(const std::string& loanID, const std::string& operatorURL, bool notify=true);
|
* @param randomSerial Always generate a new device (or not)
|
||||||
|
* @param dirName Directory where to put generated files (.adept)
|
||||||
/**
|
* @param hobbes Override hobbes default version
|
||||||
* @brief Return default ADEPT directory (ie /home/<user>/.config/adept)
|
* @param ACSServer Override main ACS server (default adeactivate.adobe.com)
|
||||||
*/
|
*/
|
||||||
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,
|
static DRMProcessor* createDRMProcessor(DRMProcessorClient* client,
|
||||||
bool randomSerial=false, std::string dirName=std::string(""),
|
bool randomSerial=false, const std::string& dirName=std::string(DEFAULT_ADEPT_DIR),
|
||||||
const std::string& hobbes=std::string(HOBBES_DEFAULT_VERSION),
|
const std::string& hobbes=std::string(HOBBES_DEFAULT_VERSION),
|
||||||
const std::string& ACSServer=ACS_SERVER);
|
const std::string& ACSServer=ACS_SERVER);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get current log level
|
* @brief Get current log level
|
||||||
*/
|
*/
|
||||||
static int getLogLevel();
|
static int getLogLevel();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set log level (higher number for verbose output)
|
* @brief Set log level (higher number for verbose output)
|
||||||
*/
|
*/
|
||||||
static void setLogLevel(int logLevel);
|
static void setLogLevel(int logLevel);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Functions used internally, should not be called by user
|
* Functions used internally, should not be called by user
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Send HTTP (GET or POST) request
|
* @brief Send HTTP (GET or POST) request
|
||||||
*
|
*
|
||||||
* @param URL HTTP URL
|
* @param URL HTTP URL
|
||||||
* @param POSTData POST data if needed, if not set, a GET request is done
|
* @param POSTData POST data if needed, if not set, a GET request is done
|
||||||
* @param contentType Optional content type of POST Data
|
* @param contentType Optional content type of POST Data
|
||||||
* @param responseHeaders Optional Response headers of HTTP request
|
* @param responseHeaders Optional Response headers of HTTP request
|
||||||
* @param fd Optional File descriptor to write received data
|
* @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)
|
* @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
|
* @return data of HTTP response
|
||||||
*/
|
*/
|
||||||
ByteArray sendRequest(const std::string& URL, const std::string& POSTData=std::string(), const char* contentType=0, std::map<std::string, std::string>* responseHeaders=0, int fd=0, bool resume=false);
|
ByteArray sendRequest(const std::string& URL, const std::string& POSTData=std::string(), const char* contentType=0, std::map<std::string, std::string>* responseHeaders=0, int fd=0, bool resume=false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @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
|
||||||
*/
|
*/
|
||||||
ByteArray encryptWithDeviceKey(const unsigned char* data, unsigned int len);
|
ByteArray encryptWithDeviceKey(const unsigned char* data, unsigned int len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief In place decrypt data with private device key
|
* @brief In place decrypt data with private device key
|
||||||
*/
|
*/
|
||||||
ByteArray decryptWithDeviceKey(const unsigned char* data, unsigned int len);
|
ByteArray decryptWithDeviceKey(const unsigned char* data, unsigned int len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return base64 encoded value of RSA public key
|
* @brief Return base64 encoded value of RSA public key
|
||||||
*/
|
*/
|
||||||
std::string serializeRSAPublicKey(void* rsa);
|
std::string serializeRSAPublicKey(void* rsa);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return base64 encoded value of RSA private key encrypted with private device key
|
* @brief Return base64 encoded value of RSA private key encrypted with private device key
|
||||||
*/
|
*/
|
||||||
std::string serializeRSAPrivateKey(void* rsa);
|
std::string serializeRSAPrivateKey(void* rsa);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Export clear private license key into path
|
* @brief Export clear private license key into path
|
||||||
*/
|
*/
|
||||||
void exportPrivateLicenseKey(std::string path);
|
void exportPrivateLicenseKey(std::string path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get current user
|
||||||
|
*/
|
||||||
|
User* getUser() { return user; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get current user
|
* @brief Get current device
|
||||||
*/
|
*/
|
||||||
User* getUser() { return user; }
|
Device* getDevice() { return device; }
|
||||||
|
|
||||||
/**
|
|
||||||
* @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);
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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:
|
private:
|
||||||
gourou::DRMProcessorClient* client;
|
gourou::DRMProcessorClient* client;
|
||||||
gourou::Device* device;
|
gourou::Device* device;
|
||||||
gourou::User* user;
|
gourou::User* user;
|
||||||
|
|
||||||
DRMProcessor(DRMProcessorClient* client);
|
DRMProcessor(DRMProcessorClient* client);
|
||||||
|
|
||||||
void pushString(void* sha_ctx, const std::string& string);
|
void pushString(void* sha_ctx, const std::string& string);
|
||||||
void pushTag(void* sha_ctx, uint8_t tag);
|
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, void *sha_ctx, std::map<std::string,std::string> nsHash);
|
||||||
void hashNode(const pugi::xml_node& root, unsigned char* sha_out);
|
void hashNode(const pugi::xml_node& root, unsigned char* sha_out);
|
||||||
void signNode(pugi::xml_node& rootNode);
|
void signNode(pugi::xml_node& rootNode);
|
||||||
void addNonce(pugi::xml_node& root);
|
void addNonce(pugi::xml_node& root);
|
||||||
void buildAuthRequest(pugi::xml_document& authReq);
|
void buildAuthRequest(pugi::xml_document& authReq);
|
||||||
void buildInitLicenseServiceRequest(pugi::xml_document& initLicReq, std::string operatorURL);
|
void buildInitLicenseServiceRequest(pugi::xml_document& initLicReq, std::string operatorURL);
|
||||||
void doOperatorAuth(std::string operatorURL);
|
void doOperatorAuth(std::string operatorURL);
|
||||||
void operatorAuth(std::string operatorURL);
|
void operatorAuth(std::string operatorURL);
|
||||||
void buildFulfillRequest(pugi::xml_document& acsmDoc, pugi::xml_document& fulfillReq);
|
void buildFulfillRequest(pugi::xml_document& acsmDoc, pugi::xml_document& fulfillReq);
|
||||||
void buildActivateReq(pugi::xml_document& activateReq);
|
void buildActivateReq(pugi::xml_document& activateReq);
|
||||||
void buildReturnReq(pugi::xml_document& returnReq, const std::string& loanID, const std::string& operatorURL);
|
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);
|
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 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 decryptADEPTKey(const std::string& encryptedKey, unsigned char* decryptedKey);
|
||||||
void notifyServer(pugi::xml_node& notifyRoot);
|
void removeEPubDRM(const std::string& filenameIn, const std::string& filenameOut, const unsigned char* encryptionKey, unsigned encryptionKeySize);
|
||||||
void notifyServer(pugi::xml_document& fulfillReply);
|
void generatePDFObjectKey(int version,
|
||||||
std::string encryptedKeyFirstPass(pugi::xml_document& rightsDoc, const std::string& encryptedKey, const std::string& keyType);
|
const unsigned char* masterKey, unsigned int masterKeyLength,
|
||||||
void decryptADEPTKey(pugi::xml_document& rightsDoc, unsigned char* decryptedKey, const unsigned char* encryptionKey=0, unsigned encryptionKeySize=0);
|
int objectId, int objectGenerationNumber,
|
||||||
void removeEPubDRM(const std::string& filenameIn, const std::string& filenameOut, const unsigned char* encryptionKey, unsigned encryptionKeySize);
|
unsigned char* keyOut);
|
||||||
void generatePDFObjectKey(int version,
|
void removePDFDRM(const std::string& filenameIn, const std::string& filenameOut, const unsigned char* encryptionKey, unsigned encryptionKeySize);
|
||||||
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);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,152 +43,135 @@ namespace gourou
|
||||||
/**
|
/**
|
||||||
* Some common utilities
|
* Some common utilities
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define ADOBE_ADEPT_NS "http://ns.adobe.com/adept"
|
#define ADOBE_ADEPT_NS "http://ns.adobe.com/adept"
|
||||||
|
|
||||||
static const int SHA1_LEN = 20;
|
static const int SHA1_LEN = 20;
|
||||||
static const int RSA_KEY_SIZE = 128;
|
static const int RSA_KEY_SIZE = 128;
|
||||||
static const int RSA_KEY_SIZE_BITS = (RSA_KEY_SIZE*8);
|
static const int RSA_KEY_SIZE_BITS = (RSA_KEY_SIZE*8);
|
||||||
|
|
||||||
enum GOUROU_ERROR {
|
enum GOUROU_ERROR {
|
||||||
GOUROU_DEVICE_DOES_NOT_MATCH = 0x1000,
|
GOUROU_DEVICE_DOES_NOT_MATCH = 0x1000,
|
||||||
GOUROU_INVALID_CLIENT,
|
GOUROU_INVALID_CLIENT,
|
||||||
GOUROU_TAG_NOT_FOUND,
|
GOUROU_TAG_NOT_FOUND,
|
||||||
GOUROU_ADEPT_ERROR,
|
GOUROU_ADEPT_ERROR,
|
||||||
GOUROU_FILE_ERROR,
|
GOUROU_FILE_ERROR,
|
||||||
GOUROU_INVALID_PROPERTY
|
GOUROU_INVALID_PROPERTY
|
||||||
};
|
};
|
||||||
|
|
||||||
enum FULFILL_ERROR {
|
enum FULFILL_ERROR {
|
||||||
FF_ACSM_FILE_NOT_EXISTS = 0x1100,
|
FF_ACSM_FILE_NOT_EXISTS = 0x1100,
|
||||||
FF_INVALID_ACSM_FILE,
|
FF_INVALID_ACSM_FILE,
|
||||||
FF_NO_HMAC_IN_ACSM_FILE,
|
FF_NO_HMAC_IN_ACSM_FILE,
|
||||||
FF_NOT_ACTIVATED,
|
FF_NOT_ACTIVATED,
|
||||||
FF_NO_OPERATOR_URL,
|
FF_NO_OPERATOR_URL
|
||||||
FF_SERVER_INTERNAL_ERROR
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DOWNLOAD_ERROR {
|
enum DOWNLOAD_ERROR {
|
||||||
DW_NO_ITEM = 0x1200,
|
DW_NO_ITEM = 0x1200,
|
||||||
DW_NO_EBX_HANDLER,
|
DW_NO_EBX_HANDLER,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum SIGNIN_ERROR {
|
enum SIGNIN_ERROR {
|
||||||
SIGN_INVALID_CREDENTIALS = 0x1300,
|
SIGN_INVALID_CREDENTIALS = 0x1300,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ACTIVATE_ERROR {
|
enum ACTIVATE_ERROR {
|
||||||
ACTIVATE_NOT_SIGNEDIN = 0x1400
|
ACTIVATE_NOT_SIGNEDIN = 0x1400
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DEV_ERROR {
|
enum DEV_ERROR {
|
||||||
DEV_MKPATH = 0x2000,
|
DEV_MKPATH = 0x2000,
|
||||||
DEV_MAC_ERROR,
|
DEV_MAC_ERROR,
|
||||||
DEV_INVALID_DEVICE_FILE,
|
DEV_INVALID_DEVICE_FILE,
|
||||||
DEV_INVALID_DEVICE_KEY_FILE,
|
DEV_INVALID_DEVICE_KEY_FILE,
|
||||||
DEV_INVALID_DEV_PROPERTY,
|
DEV_INVALID_DEV_PROPERTY,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum USER_ERROR {
|
enum USER_ERROR {
|
||||||
USER_MKPATH = 0x3000,
|
USER_MKPATH = 0x3000,
|
||||||
USER_INVALID_ACTIVATION_FILE,
|
USER_INVALID_ACTIVATION_FILE,
|
||||||
USER_NO_AUTHENTICATION_URL,
|
USER_NO_AUTHENTICATION_URL,
|
||||||
USER_NO_PROPERTY,
|
USER_NO_PROPERTY,
|
||||||
USER_INVALID_INPUT,
|
USER_INVALID_INPUT,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum FULFILL_ITEM_ERROR {
|
enum FULFILL_ITEM_ERROR {
|
||||||
FFI_INVALID_FULFILLMENT_DATA = 0x4000,
|
FFI_INVALID_FULFILLMENT_DATA = 0x4000,
|
||||||
FFI_INVALID_LOAN_TOKEN
|
FFI_INVALID_LOAN_TOKEN
|
||||||
};
|
};
|
||||||
|
|
||||||
enum CLIENT_ERROR {
|
enum CLIENT_ERROR {
|
||||||
CLIENT_BAD_PARAM = 0x5000,
|
CLIENT_BAD_PARAM = 0x5000,
|
||||||
CLIENT_INVALID_PKCS12,
|
CLIENT_INVALID_PKCS12,
|
||||||
CLIENT_INVALID_CERTIFICATE,
|
CLIENT_INVALID_CERTIFICATE,
|
||||||
CLIENT_NO_PRIV_KEY,
|
CLIENT_NO_PRIV_KEY,
|
||||||
CLIENT_NO_PUB_KEY,
|
CLIENT_RSA_ERROR,
|
||||||
CLIENT_RSA_ERROR,
|
CLIENT_BAD_CHAINING,
|
||||||
CLIENT_BAD_CHAINING,
|
CLIENT_BAD_KEY_SIZE,
|
||||||
CLIENT_BAD_KEY_SIZE,
|
CLIENT_BAD_ZIP_FILE,
|
||||||
CLIENT_BAD_ZIP_FILE,
|
CLIENT_ZIP_ERROR,
|
||||||
CLIENT_ZIP_ERROR,
|
CLIENT_GENERIC_EXCEPTION,
|
||||||
CLIENT_GENERIC_EXCEPTION,
|
CLIENT_NETWORK_ERROR,
|
||||||
CLIENT_NETWORK_ERROR,
|
CLIENT_INVALID_PKCS8,
|
||||||
CLIENT_INVALID_PKCS8,
|
CLIENT_FILE_ERROR,
|
||||||
CLIENT_FILE_ERROR,
|
CLIENT_OSSL_ERROR,
|
||||||
CLIENT_OSSL_ERROR,
|
|
||||||
CLIENT_CRYPT_ERROR,
|
|
||||||
CLIENT_DIGEST_ERROR,
|
|
||||||
CLIENT_HTTP_ERROR
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DRM_REMOVAL_ERROR {
|
enum DRM_REMOVAL_ERROR {
|
||||||
DRM_ERR_ENCRYPTION_KEY = 0x6000,
|
DRM_ERR_ENCRYPTION_KEY = 0x6000,
|
||||||
DRM_VERSION_NOT_SUPPORTED,
|
DRM_VERSION_NOT_SUPPORTED,
|
||||||
DRM_FILE_ERROR,
|
DRM_FILE_ERROR,
|
||||||
DRM_FORMAT_NOT_SUPPORTED,
|
DRM_FORMAT_NOT_SUPPORTED,
|
||||||
DRM_IN_OUT_EQUALS,
|
DRM_IN_OUT_EQUALS,
|
||||||
DRM_MISSING_PARAMETER,
|
DRM_MISSING_PARAMETER,
|
||||||
DRM_INVALID_KEY_SIZE,
|
DRM_INVALID_KEY_SIZE
|
||||||
DRM_ERR_ENCRYPTION_KEY_FP,
|
|
||||||
DRM_INVALID_USER
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef _NOEXCEPT
|
|
||||||
#if __STDC_VERSION__ >= 201112L
|
|
||||||
# define _NOEXCEPT noexcept
|
|
||||||
# define _NOEXCEPT_(x) noexcept(x)
|
|
||||||
#else
|
|
||||||
# define _NOEXCEPT throw()
|
|
||||||
# define _NOEXCEPT_(x)
|
|
||||||
#endif
|
|
||||||
#endif /* !_NOEXCEPT */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic exception class
|
* Generic exception class
|
||||||
*/
|
*/
|
||||||
class Exception : public std::exception
|
class Exception : public std::exception
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Exception(int code, const char* message, const char* file, int line):
|
Exception(int code, const char* message, const char* file, int line):
|
||||||
code(code), line(line), file(file)
|
code(code), line(line), file(file)
|
||||||
{
|
{
|
||||||
std::stringstream msg;
|
std::stringstream msg;
|
||||||
msg << "Exception code : 0x" << std::setbase(16) << code << std::endl;
|
msg << "Exception code : 0x" << std::setbase(16) << code << std::endl;
|
||||||
msg << "Message : " << message << std::endl;
|
msg << "Message : " << message << std::endl;
|
||||||
if (logLevel >= LG_LOG_DEBUG)
|
if (logLevel >= DEBUG)
|
||||||
msg << "File : " << file << ":" << std::setbase(10) << line << std::endl;
|
msg << "File : " << file << ":" << std::setbase(10) << line << std::endl;
|
||||||
fullmessage = strdup(msg.str().c_str());
|
fullmessage = strdup(msg.str().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
Exception(const Exception& other)
|
Exception(const Exception& other)
|
||||||
{
|
{
|
||||||
this->code = other.code;
|
this->code = other.code;
|
||||||
this->line = other.line;
|
this->line = line;
|
||||||
this->file = other.file;
|
this->file = file;
|
||||||
this->fullmessage = strdup(other.fullmessage);
|
this->fullmessage = strdup(other.fullmessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
~Exception() _NOEXCEPT
|
~Exception()
|
||||||
{
|
{
|
||||||
free(fullmessage);
|
free(fullmessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char * what () const throw () { return fullmessage; }
|
const char * what () const throw () { return fullmessage; }
|
||||||
|
|
||||||
int getErrorCode() {return code;}
|
int getErrorCode() {return code;}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int code, line;
|
int code, line;
|
||||||
const char* file;
|
const char* message, *file;
|
||||||
char* fullmessage;
|
char* fullmessage;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Throw an exception
|
* @brief Throw an exception
|
||||||
*/
|
*/
|
||||||
#define EXCEPTION(code, message) \
|
#define EXCEPTION(code, message) \
|
||||||
{std::stringstream __msg;__msg << message; throw gourou::Exception(code, __msg.str().c_str(), __FILE__, __LINE__);}
|
{std::stringstream __msg;__msg << message; throw gourou::Exception(code, __msg.str().c_str(), __FILE__, __LINE__);}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -197,15 +180,15 @@ namespace gourou
|
||||||
class StringXMLWriter : public pugi::xml_writer
|
class StringXMLWriter : public pugi::xml_writer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void write(const void* data, size_t size)
|
virtual void write(const void* data, size_t size)
|
||||||
{
|
{
|
||||||
result.append(static_cast<const char*>(data), size);
|
result.append(static_cast<const char*>(data), size);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& getResult() {return result;}
|
const std::string& getResult() {return result;}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string result;
|
std::string result;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char* ws = " \t\n\r\f\v";
|
static const char* ws = " \t\n\r\f\v";
|
||||||
|
|
@ -215,8 +198,8 @@ namespace gourou
|
||||||
*/
|
*/
|
||||||
inline std::string& rtrim(std::string& s, const char* t = ws)
|
inline std::string& rtrim(std::string& s, const char* t = ws)
|
||||||
{
|
{
|
||||||
s.erase(s.find_last_not_of(t) + 1);
|
s.erase(s.find_last_not_of(t) + 1);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -224,8 +207,8 @@ namespace gourou
|
||||||
*/
|
*/
|
||||||
inline std::string& ltrim(std::string& s, const char* t = ws)
|
inline std::string& ltrim(std::string& s, const char* t = ws)
|
||||||
{
|
{
|
||||||
s.erase(0, s.find_first_not_of(t));
|
s.erase(0, s.find_first_not_of(t));
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -233,23 +216,7 @@ namespace gourou
|
||||||
*/
|
*/
|
||||||
inline std::string& trim(std::string& s, const char* t = ws)
|
inline std::string& trim(std::string& s, const char* t = ws)
|
||||||
{
|
{
|
||||||
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)
|
|
||||||
{
|
|
||||||
pugi::xpath_node xpath_node = root.select_node(tagName);
|
|
||||||
|
|
||||||
if (!xpath_node)
|
|
||||||
{
|
|
||||||
if (throwOnNull)
|
|
||||||
EXCEPTION(GOUROU_TAG_NOT_FOUND, "Tag " << tagName << " not found");
|
|
||||||
|
|
||||||
return pugi::xml_node();
|
|
||||||
}
|
|
||||||
|
|
||||||
return xpath_node.node();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -257,68 +224,55 @@ namespace gourou
|
||||||
* It can throw an exception if tag does not exists
|
* It can throw an exception if tag does not exists
|
||||||
* or just return an empty value
|
* or just return an empty value
|
||||||
*/
|
*/
|
||||||
static inline std::string extractTextElem(const pugi::xml_node& root, const char* tagName, bool throwOnNull=true)
|
static inline std::string extractTextElem(const pugi::xml_document& doc, const char* tagName, bool throwOnNull=true)
|
||||||
{
|
{
|
||||||
pugi::xml_node node = getNode(root, tagName, throwOnNull);
|
pugi::xpath_node xpath_node = doc.select_node(tagName);
|
||||||
|
|
||||||
node = node.first_child();
|
|
||||||
|
|
||||||
if (!node)
|
|
||||||
{
|
|
||||||
if (throwOnNull)
|
|
||||||
EXCEPTION(GOUROU_TAG_NOT_FOUND, "Text element for tag " << tagName << " not found");
|
|
||||||
|
|
||||||
|
if (!xpath_node)
|
||||||
|
{
|
||||||
|
if (throwOnNull)
|
||||||
|
EXCEPTION(GOUROU_TAG_NOT_FOUND, "Tag " << tagName << " not found");
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string res = node.value();
|
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);
|
return trim(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static inline std::string extractTextElem(const pugi::xml_node& doc, const char* tagName, bool throwOnNull=true)
|
||||||
* @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);
|
pugi::xpath_node xpath_node = doc.select_node(tagName);
|
||||||
|
|
||||||
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
|
|
||||||
* It can throw an exception if attribute does not exists
|
|
||||||
* or just return an empty value
|
|
||||||
*/
|
|
||||||
static inline std::string extractTextAttribute(const pugi::xml_node& root, const char* tagName, const char* attributeName, bool throwOnNull=true)
|
|
||||||
{
|
|
||||||
pugi::xml_node node = getNode(root, tagName, throwOnNull);
|
|
||||||
|
|
||||||
pugi::xml_attribute attr = node.attribute(attributeName);
|
|
||||||
|
|
||||||
if (!attr)
|
|
||||||
{
|
|
||||||
if (throwOnNull)
|
|
||||||
EXCEPTION(GOUROU_TAG_NOT_FOUND, "Attribute element " << attributeName << " for tag " << tagName << " not found");
|
|
||||||
|
|
||||||
|
if (!xpath_node)
|
||||||
|
{
|
||||||
|
if (throwOnNull)
|
||||||
|
EXCEPTION(GOUROU_TAG_NOT_FOUND, "Tag " << tagName << " not found");
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string res = attr.value();
|
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);
|
return trim(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -331,31 +285,8 @@ namespace gourou
|
||||||
*/
|
*/
|
||||||
static inline void appendTextElem(pugi::xml_node& root, const std::string& name, const std::string& value)
|
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());
|
pugi::xml_node node = root.append_child(name.c_str());
|
||||||
node.append_child(pugi::node_pcdata).set_value(value.c_str());
|
node.append_child(pugi::node_pcdata).set_value(value.c_str());
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove "urn:uuid:" prefix and all '-' from uuid
|
|
||||||
* urn:uuid:9cb786e8-586a-4950-8901-fff8d2ee6025
|
|
||||||
* ->
|
|
||||||
* 9cb786e8586a49508901fff8d2ee6025
|
|
||||||
*/
|
|
||||||
static inline std::string extractIdFromUUID(const std::string& uuid)
|
|
||||||
{
|
|
||||||
unsigned int i = 0;
|
|
||||||
std::string res;
|
|
||||||
|
|
||||||
if (uuid.find("urn:uuid:") == 0)
|
|
||||||
i = 9;
|
|
||||||
|
|
||||||
for(; i<uuid.size(); i++)
|
|
||||||
{
|
|
||||||
if (uuid[i] != '-')
|
|
||||||
res += uuid[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -365,31 +296,31 @@ namespace gourou
|
||||||
*/
|
*/
|
||||||
static inline int createNewFile(std::string path, bool truncate=true)
|
static inline int createNewFile(std::string path, bool truncate=true)
|
||||||
{
|
{
|
||||||
int options = O_CREAT|O_WRONLY;
|
int options = O_CREAT|O_WRONLY;
|
||||||
if (truncate)
|
if (truncate)
|
||||||
options |= O_TRUNC;
|
options |= O_TRUNC;
|
||||||
else
|
else
|
||||||
options |= O_APPEND;
|
options |= O_APPEND;
|
||||||
|
|
||||||
int fd = open(path.c_str(), options, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
|
int fd = open(path.c_str(), options, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
|
||||||
|
|
||||||
if (fd <= 0)
|
if (fd <= 0)
|
||||||
EXCEPTION(GOUROU_FILE_ERROR, "Unable to create " << path);
|
EXCEPTION(GOUROU_FILE_ERROR, "Unable to create " << path);
|
||||||
|
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Write data in a file. If it already exists, it's truncated
|
* @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)
|
static inline void writeFile(std::string path, const unsigned char* data, unsigned int length)
|
||||||
{
|
{
|
||||||
int fd = createNewFile(path);
|
int fd = createNewFile(path);
|
||||||
|
|
||||||
|
if (write(fd, data, length) != length)
|
||||||
|
EXCEPTION(GOUROU_FILE_ERROR, "Write error for file " << path);
|
||||||
|
|
||||||
if (write(fd, data, length) != length)
|
close (fd);
|
||||||
EXCEPTION(GOUROU_FILE_ERROR, "Write error for file " << path);
|
|
||||||
|
|
||||||
close (fd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -397,7 +328,7 @@ namespace gourou
|
||||||
*/
|
*/
|
||||||
static inline void writeFile(std::string path, ByteArray& data)
|
static inline void writeFile(std::string path, ByteArray& data)
|
||||||
{
|
{
|
||||||
writeFile(path, data.data(), data.length());
|
writeFile(path, data.data(), data.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -405,7 +336,7 @@ namespace gourou
|
||||||
*/
|
*/
|
||||||
static inline void writeFile(std::string path, const std::string& data)
|
static inline void writeFile(std::string path, const std::string& data)
|
||||||
{
|
{
|
||||||
writeFile(path, (const unsigned char*)data.c_str(), data.length());
|
writeFile(path, (const unsigned char*)data.c_str(), data.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -413,15 +344,15 @@ namespace gourou
|
||||||
*/
|
*/
|
||||||
static inline void readFile(std::string path, const unsigned char* data, unsigned int length)
|
static inline void readFile(std::string path, const unsigned char* data, unsigned int length)
|
||||||
{
|
{
|
||||||
int fd = open(path.c_str(), O_RDONLY);
|
int fd = open(path.c_str(), O_RDONLY);
|
||||||
|
|
||||||
if (fd <= 0)
|
if (fd <= 0)
|
||||||
EXCEPTION(GOUROU_FILE_ERROR, "Unable to open " << path);
|
EXCEPTION(GOUROU_FILE_ERROR, "Unable to open " << path);
|
||||||
|
|
||||||
if (read(fd, (void*)data, length) != length)
|
if (read(fd, (void*)data, length) != length)
|
||||||
EXCEPTION(GOUROU_FILE_ERROR, "Read error for file " << path);
|
EXCEPTION(GOUROU_FILE_ERROR, "Read error for file " << path);
|
||||||
|
|
||||||
close (fd);
|
close (fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PATH_MAX_STRING_SIZE 256
|
#define PATH_MAX_STRING_SIZE 256
|
||||||
|
|
@ -429,73 +360,59 @@ namespace gourou
|
||||||
// https://gist.github.com/ChisholmKyle/0cbedcd3e64132243a39
|
// https://gist.github.com/ChisholmKyle/0cbedcd3e64132243a39
|
||||||
/* recursive mkdir */
|
/* recursive mkdir */
|
||||||
static inline int mkdir_p(const char *dir, const mode_t mode) {
|
static inline int mkdir_p(const char *dir, const mode_t mode) {
|
||||||
char tmp[PATH_MAX_STRING_SIZE];
|
char tmp[PATH_MAX_STRING_SIZE];
|
||||||
char *p = NULL;
|
char *p = NULL;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
size_t len;
|
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';
|
||||||
|
|
||||||
/* copy path */
|
/* remove trailing slash */
|
||||||
len = strnlen (dir, PATH_MAX_STRING_SIZE);
|
if(tmp[len - 1] == '/') {
|
||||||
if (len == 0 || len == PATH_MAX_STRING_SIZE) {
|
tmp[len - 1] = '\0';
|
||||||
return -1;
|
}
|
||||||
}
|
|
||||||
memcpy (tmp, dir, len);
|
|
||||||
tmp[len] = '\0';
|
|
||||||
|
|
||||||
/* remove trailing slash */
|
/* check if path exists and is a directory */
|
||||||
if(tmp[len - 1] == '/') {
|
if (stat (tmp, &sb) == 0) {
|
||||||
tmp[len - 1] = '\0';
|
if (S_ISDIR (sb.st_mode)) {
|
||||||
}
|
return 0;
|
||||||
|
}
|
||||||
/* check if path exists and is a directory */
|
}
|
||||||
if (stat (tmp, &sb) == 0) {
|
|
||||||
if (S_ISDIR (sb.st_mode)) {
|
/* recursive mkdir */
|
||||||
return 0;
|
for(p = tmp + 1; *p; p++) {
|
||||||
}
|
if(*p == '/') {
|
||||||
}
|
*p = 0;
|
||||||
|
/* test path */
|
||||||
/* recursive mkdir */
|
if (stat(tmp, &sb) != 0) {
|
||||||
for(p = tmp + 1; *p; p++) {
|
/* path does not exist - create directory */
|
||||||
if(*p == '/') {
|
if (mkdir(tmp, mode) < 0) {
|
||||||
*p = 0;
|
return -1;
|
||||||
/* test path */
|
}
|
||||||
if (stat(tmp, &sb) != 0) {
|
} else if (!S_ISDIR(sb.st_mode)) {
|
||||||
/* path does not exist - create directory */
|
/* not a directory */
|
||||||
if (mkdir(tmp, mode) < 0) {
|
return -1;
|
||||||
return -1;
|
}
|
||||||
}
|
*p = '/';
|
||||||
} else if (!S_ISDIR(sb.st_mode)) {
|
}
|
||||||
/* not a directory */
|
}
|
||||||
return -1;
|
/* test path */
|
||||||
}
|
if (stat(tmp, &sb) != 0) {
|
||||||
*p = '/';
|
/* path does not exist - create directory */
|
||||||
}
|
if (mkdir(tmp, mode) < 0) {
|
||||||
}
|
return -1;
|
||||||
/* test path */
|
}
|
||||||
if (stat(tmp, &sb) != 0) {
|
} else if (!S_ISDIR(sb.st_mode)) {
|
||||||
/* path does not exist - create directory */
|
/* not a directory */
|
||||||
if (mkdir(tmp, mode) < 0) {
|
return -1;
|
||||||
return -1;
|
}
|
||||||
}
|
return 0;
|
||||||
} else if (!S_ISDIR(sb.st_mode)) {
|
|
||||||
/* not a directory */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void dumpBuffer(GOUROU_LOG_LEVEL level, const char* title, const unsigned char* data, unsigned int len)
|
|
||||||
{
|
|
||||||
if (gourou::logLevel < level)
|
|
||||||
return;
|
|
||||||
|
|
||||||
printf("%s", title);
|
|
||||||
for(unsigned int i=0; i<len; i++)
|
|
||||||
{
|
|
||||||
if (i && !(i%16)) printf("\n");
|
|
||||||
printf("%02x ", data[i]);
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,16 +24,16 @@
|
||||||
|
|
||||||
namespace gourou {
|
namespace gourou {
|
||||||
enum GOUROU_LOG_LEVEL {
|
enum GOUROU_LOG_LEVEL {
|
||||||
LG_LOG_ERROR,
|
ERROR,
|
||||||
LG_LOG_WARN,
|
WARN,
|
||||||
LG_LOG_INFO,
|
INFO,
|
||||||
LG_LOG_DEBUG,
|
DEBUG,
|
||||||
LG_LOG_TRACE
|
TRACE
|
||||||
};
|
};
|
||||||
|
|
||||||
extern GOUROU_LOG_LEVEL logLevel;
|
extern GOUROU_LOG_LEVEL logLevel;
|
||||||
|
|
||||||
#define GOUROU_LOG(__lvl, __msg) if (gourou::LG_LOG_##__lvl <= gourou::logLevel) {std::cout << __msg << std::endl << std::flush;}
|
#define GOUROU_LOG(__lvl, __msg) if (__lvl <= gourou::logLevel) {std::cout << __msg << std::endl << std::flush;}
|
||||||
#define GOUROU_LOG_FUNC() GOUROU_LOG(TRACE, __FUNCTION__ << "() @ " << __FILE__ << ":" << __LINE__)
|
#define GOUROU_LOG_FUNC() GOUROU_LOG(TRACE, __FUNCTION__ << "() @ " << __FILE__ << ":" << __LINE__)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -32,21 +32,21 @@ namespace gourou
|
||||||
class LoanToken
|
class LoanToken
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Main constructor. Not to be called by user
|
* @brief Main constructor. Not to be called by user
|
||||||
*
|
*
|
||||||
* @param doc Fulfill reply
|
* @param doc Fulfill reply
|
||||||
*/
|
*/
|
||||||
LoanToken(pugi::xml_document& doc);
|
LoanToken(pugi::xml_document& doc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get a property (id, operatorURL, validity)
|
* @brief Get a property (id, operatorURL, validity)
|
||||||
*/
|
*/
|
||||||
std::string getProperty(const std::string& property, const std::string& _default=std::string(""));
|
std::string getProperty(const std::string& property, const std::string& _default=std::string(""));
|
||||||
std::string operator[](const std::string& property);
|
std::string operator[](const std::string& property);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::map<std::string, std::string> properties;
|
std::map<std::string, std::string> properties;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
120
include/user.h
120
include/user.h
|
|
@ -30,7 +30,7 @@
|
||||||
namespace gourou
|
namespace gourou
|
||||||
{
|
{
|
||||||
class DRMProcessor;
|
class DRMProcessor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This class is a container for activation.xml (activation info). It should not be used by user.
|
* @brief This class is a container for activation.xml (activation info). It should not be used by user.
|
||||||
*/
|
*/
|
||||||
|
|
@ -39,73 +39,73 @@ namespace gourou
|
||||||
public:
|
public:
|
||||||
User(DRMProcessor* processor, const std::string& activationFile);
|
User(DRMProcessor* processor, const std::string& activationFile);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Retrieve some values from activation.xml
|
* @brief Retrieve some values from activation.xml
|
||||||
*/
|
*/
|
||||||
std::string& getUUID();
|
std::string& getUUID();
|
||||||
std::string& getPKCS12();
|
std::string& getPKCS12();
|
||||||
std::string& getDeviceUUID();
|
std::string& getDeviceUUID();
|
||||||
std::string& getDeviceFingerprint();
|
std::string& getDeviceFingerprint();
|
||||||
std::string& getUsername();
|
std::string& getUsername();
|
||||||
std::string& getLoginMethod();
|
std::string& getLoginMethod();
|
||||||
std::string getLicenseServiceCertificate(std::string url);
|
std::string getLicenseServiceCertificate(std::string url);
|
||||||
std::string& getAuthenticationCertificate();
|
std::string& getAuthenticationCertificate();
|
||||||
std::string& getPrivateLicenseKey();
|
std::string& getPrivateLicenseKey();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read activation.xml and put result into doc
|
* @brief Read activation.xml and put result into doc
|
||||||
*/
|
*/
|
||||||
void readActivation(pugi::xml_document& doc);
|
void readActivation(pugi::xml_document& doc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Update activation.xml with new data
|
* @brief Update activation.xml with new data
|
||||||
*/
|
*/
|
||||||
void updateActivationFile(const char* data);
|
void updateActivationFile(const char* data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Update activation.xml with doc data
|
* @brief Update activation.xml with doc data
|
||||||
*/
|
*/
|
||||||
void updateActivationFile(const pugi::xml_document& doc);
|
void updateActivationFile(const pugi::xml_document& doc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get one value of activation.xml
|
* @brief Get one value of activation.xml
|
||||||
*/
|
*/
|
||||||
std::string getProperty(const std::string property);
|
std::string getProperty(const std::string property);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get all nodes with property name
|
* @brief Get all nodes with property name
|
||||||
*/
|
*/
|
||||||
pugi::xpath_node_set getProperties(const std::string property);
|
pugi::xpath_node_set getProperties(const std::string property);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create activation.xml and devicesalt files if they did not exists
|
* @brief Create activation.xml and devicesalt files if they did not exists
|
||||||
*
|
*
|
||||||
* @param processor Instance of DRMProcessor
|
* @param processor Instance of DRMProcessor
|
||||||
* @param dirName Directory where to put files (.adept)
|
* @param dirName Directory where to put files (.adept)
|
||||||
* @param ACSServer Server used for signIn
|
* @param ACSServer Server used for signIn
|
||||||
*/
|
*/
|
||||||
static User* createUser(DRMProcessor* processor, const std::string& dirName, const std::string& ACSServer);
|
static User* createUser(DRMProcessor* processor, const std::string& dirName, const std::string& ACSServer);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DRMProcessor* processor;
|
DRMProcessor* processor;
|
||||||
pugi::xml_document activationDoc;
|
pugi::xml_document activationDoc;
|
||||||
|
|
||||||
std::string activationFile;
|
std::string activationFile;
|
||||||
std::string pkcs12;
|
std::string pkcs12;
|
||||||
std::string uuid;
|
std::string uuid;
|
||||||
std::string deviceUUID;
|
std::string deviceUUID;
|
||||||
std::string deviceFingerprint;
|
std::string deviceFingerprint;
|
||||||
std::string username;
|
std::string username;
|
||||||
std::string loginMethod;
|
std::string loginMethod;
|
||||||
std::map<std::string,std::string> licenseServiceCertificates;
|
std::map<std::string,std::string> licenseServiceCertificates;
|
||||||
std::string authenticationCertificate;
|
std::string authenticationCertificate;
|
||||||
std::string privateLicenseKey;
|
std::string privateLicenseKey;
|
||||||
|
|
||||||
User(DRMProcessor* processor);
|
User(DRMProcessor* processor);
|
||||||
|
|
||||||
void parseActivationFile(bool throwOnNull=true);
|
void parseActivationFile(bool throwOnNull=true);
|
||||||
ByteArray signIn(const std::string& adobeID, const std::string& adobePassword,
|
ByteArray signIn(const std::string& adobeID, const std::string& adobePassword,
|
||||||
ByteArray authenticationCertificate);
|
ByteArray authenticationCertificate);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,21 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Pugixml
|
||||||
|
if [ ! -d lib/pugixml ] ; then
|
||||||
|
git clone https://github.com/zeux/pugixml.git lib/pugixml
|
||||||
|
pushd lib/pugixml
|
||||||
|
git checkout latest
|
||||||
|
popd
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Base64
|
||||||
|
if [ ! -d lib/base64 ] ; then
|
||||||
|
git clone https://gist.github.com/f0fd86b6c73063283afe550bc5d77594.git lib/base64
|
||||||
|
fi
|
||||||
|
|
||||||
# uPDFParser
|
# uPDFParser
|
||||||
if [ ! -d lib/updfparser ] ; then
|
if [ ! -d lib/updfparser ] ; then
|
||||||
git clone https://forge.soutade.fr/soutade/uPDFParser.git lib/updfparser
|
git clone git://soutade.fr/updfparser.git lib/updfparser
|
||||||
pushd lib/updfparser
|
pushd lib/updfparser
|
||||||
make BUILD_STATIC=1 BUILD_SHARED=0
|
make BUILD_STATIC=1 BUILD_SHARED=0
|
||||||
popd
|
popd
|
||||||
|
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
if [ ! -d lib/updfparser ] ; then
|
|
||||||
echo "Some libraries are missing"
|
|
||||||
echo "You must run this script at the top of libgourou working direcotry."
|
|
||||||
echo "./scripts/setup.sh must be called first (make all)"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# uPDFParser
|
|
||||||
pushd lib/updfparser
|
|
||||||
git pull origin master
|
|
||||||
make clean all BUILD_STATIC=1 BUILD_SHARED=0
|
|
||||||
|
|
@ -17,241 +17,199 @@
|
||||||
along with libgourou. If not, see <http://www.gnu.org/licenses/>.
|
along with libgourou. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
#include <Base64.h>
|
#include <base64/Base64.h>
|
||||||
|
|
||||||
#include <bytearray.h>
|
#include <bytearray.h>
|
||||||
|
|
||||||
namespace gourou
|
namespace gourou
|
||||||
{
|
{
|
||||||
std::map<unsigned char*, int> ByteArray::refCounter;
|
std::map<unsigned char*, int> ByteArray::refCounter;
|
||||||
|
|
||||||
ByteArray::ByteArray(bool useMalloc):_useMalloc(useMalloc), _data(0), _length(0)
|
ByteArray::ByteArray(bool useMalloc):_useMalloc(useMalloc), _data(0), _length(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
ByteArray::ByteArray(unsigned int length, bool useMalloc):
|
ByteArray::ByteArray(unsigned int length, bool useMalloc):
|
||||||
_useMalloc(useMalloc)
|
_useMalloc(useMalloc)
|
||||||
{
|
{
|
||||||
initData(0, length);
|
initData(0, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteArray::ByteArray(const unsigned char* data, unsigned int length):
|
ByteArray::ByteArray(const unsigned char* data, unsigned int length):
|
||||||
_useMalloc(false)
|
_useMalloc(false)
|
||||||
{
|
{
|
||||||
initData(data, length);
|
initData(data, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteArray::ByteArray(const char* data, int length):
|
ByteArray::ByteArray(const char* data, int length):
|
||||||
_useMalloc(false)
|
_useMalloc(false)
|
||||||
{
|
{
|
||||||
if (length == -1)
|
if (length == -1)
|
||||||
length = strlen(data);
|
length = strlen(data);
|
||||||
|
|
||||||
initData((unsigned char*)data, (unsigned int) length);
|
initData((unsigned char*)data, (unsigned int) length);
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteArray::ByteArray(const std::string& str):
|
ByteArray::ByteArray(const std::string& str):
|
||||||
_useMalloc(false)
|
_useMalloc(false)
|
||||||
{
|
{
|
||||||
initData((unsigned char*)str.c_str(), (unsigned int)str.length());
|
initData((unsigned char*)str.c_str(), (unsigned int)str.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ByteArray::initData(const unsigned char* data, unsigned int length)
|
void ByteArray::initData(const unsigned char* data, unsigned int length)
|
||||||
{
|
{
|
||||||
if (_useMalloc)
|
if (_useMalloc)
|
||||||
_data = (unsigned char*)malloc(length);
|
_data = (unsigned char*)malloc(length);
|
||||||
else
|
else
|
||||||
_data = new unsigned char[length];
|
_data = new unsigned char[length];
|
||||||
|
|
||||||
if (data)
|
if (data)
|
||||||
memcpy((void*)_data, data, length);
|
memcpy((void*)_data, data, length);
|
||||||
|
|
||||||
_length = length;
|
_length = length;
|
||||||
|
|
||||||
addRef();
|
addRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteArray::ByteArray(const ByteArray& other)
|
ByteArray::ByteArray(const ByteArray& other)
|
||||||
{
|
{
|
||||||
this->_useMalloc = other._useMalloc;
|
this->_useMalloc = other._useMalloc;
|
||||||
this->_data = other._data;
|
this->_data = other._data;
|
||||||
this->_length = other._length;
|
this->_length = other._length;
|
||||||
|
|
||||||
addRef();
|
addRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteArray& ByteArray::operator=(const ByteArray& other)
|
ByteArray& ByteArray::operator=(const ByteArray& other)
|
||||||
{
|
{
|
||||||
delRef();
|
delRef();
|
||||||
|
|
||||||
|
this->_useMalloc = other._useMalloc;
|
||||||
|
this->_data = other._data;
|
||||||
|
this->_length = other._length;
|
||||||
|
|
||||||
this->_useMalloc = other._useMalloc;
|
addRef();
|
||||||
this->_data = other._data;
|
|
||||||
this->_length = other._length;
|
return *this;
|
||||||
|
|
||||||
addRef();
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteArray::~ByteArray()
|
ByteArray::~ByteArray()
|
||||||
{
|
{
|
||||||
delRef();
|
delRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ByteArray::addRef()
|
void ByteArray::addRef()
|
||||||
{
|
{
|
||||||
if (!_data) return;
|
if (!_data) return;
|
||||||
|
|
||||||
if (refCounter.count(_data) == 0)
|
if (refCounter.count(_data) == 0)
|
||||||
refCounter[_data] = 1;
|
refCounter[_data] = 1;
|
||||||
else
|
else
|
||||||
refCounter[_data]++;
|
refCounter[_data]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ByteArray::delRef()
|
void ByteArray::delRef()
|
||||||
{
|
{
|
||||||
if (!_data) return;
|
if (!_data) return;
|
||||||
|
|
||||||
if (refCounter[_data] == 1)
|
if (refCounter[_data] == 1)
|
||||||
{
|
{
|
||||||
if (_useMalloc)
|
if (_useMalloc)
|
||||||
free(_data);
|
free(_data);
|
||||||
else
|
else
|
||||||
delete[] _data;
|
delete[] _data;
|
||||||
refCounter.erase(_data);
|
refCounter.erase(_data);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
refCounter[_data]--;
|
refCounter[_data]--;
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteArray ByteArray::fromBase64(const ByteArray& other)
|
ByteArray ByteArray::fromBase64(const ByteArray& other)
|
||||||
{
|
{
|
||||||
std::string b64;
|
std::string b64;
|
||||||
|
|
||||||
macaron::Base64::Decode(std::string((char*)other._data, other._length), b64);
|
macaron::Base64::Decode(std::string((char*)other._data, other._length), b64);
|
||||||
|
|
||||||
return ByteArray(b64);
|
return ByteArray(b64);
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteArray ByteArray::fromBase64(const char* data, int length)
|
ByteArray ByteArray::fromBase64(const char* data, int length)
|
||||||
{
|
{
|
||||||
std::string b64;
|
std::string b64;
|
||||||
|
|
||||||
if (length == -1)
|
if (length == -1)
|
||||||
length = strlen(data);
|
length = strlen(data);
|
||||||
|
|
||||||
|
macaron::Base64::Decode(std::string(data, length), b64);
|
||||||
|
|
||||||
macaron::Base64::Decode(std::string(data, length), b64);
|
return ByteArray(b64);
|
||||||
|
|
||||||
return ByteArray(b64);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteArray ByteArray::fromBase64(const std::string& str)
|
ByteArray ByteArray::fromBase64(const std::string& str)
|
||||||
{
|
{
|
||||||
return ByteArray::fromBase64(str.c_str(), str.length());
|
return ByteArray::fromBase64(str.c_str(), str.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ByteArray::toBase64()
|
std::string ByteArray::toBase64()
|
||||||
{
|
{
|
||||||
return macaron::Base64::Encode(std::string((char*)_data, _length));
|
return macaron::Base64::Encode(std::string((char*)_data, _length));
|
||||||
}
|
|
||||||
|
|
||||||
ByteArray ByteArray::fromHex(const std::string& str)
|
|
||||||
{
|
|
||||||
if (str.size() % 2)
|
|
||||||
throw std::invalid_argument("Size of hex string not multiple of 2");
|
|
||||||
|
|
||||||
ByteArray res((unsigned int)(str.size()/2));
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
unsigned char* data = res.data();
|
|
||||||
unsigned char cur, tmp;
|
|
||||||
|
|
||||||
for (i=0; i<str.size(); i+=2)
|
|
||||||
{
|
|
||||||
cur = 0;
|
|
||||||
|
|
||||||
tmp = str[i];
|
|
||||||
if (tmp >= 'a' && tmp <= 'f')
|
|
||||||
cur = (tmp - 'a' + 10) << 4;
|
|
||||||
else if (tmp >= 'A' && tmp <= 'F')
|
|
||||||
cur = (tmp - 'A' + 10) << 4;
|
|
||||||
else if (tmp >= '0' && tmp <= '9')
|
|
||||||
cur = (tmp - '0') << 4;
|
|
||||||
else
|
|
||||||
throw std::invalid_argument("Invalid character in hex string");
|
|
||||||
|
|
||||||
tmp = str[i+1];
|
|
||||||
if (tmp >= 'a' && tmp <= 'f')
|
|
||||||
cur += tmp - 'a' + 10;
|
|
||||||
else if (tmp >= 'A' && tmp <= 'F')
|
|
||||||
cur += tmp - 'A' + 10;
|
|
||||||
else if (tmp >= '0' && tmp <= '9')
|
|
||||||
cur += tmp - '0';
|
|
||||||
else
|
|
||||||
throw std::invalid_argument("Invalid character in hex string");
|
|
||||||
|
|
||||||
data[i/2] = cur;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ByteArray::toHex()
|
std::string ByteArray::toHex()
|
||||||
{
|
{
|
||||||
char* tmp = new char[_length*2+1];
|
char* tmp = new char[_length*2+1];
|
||||||
|
|
||||||
for(int i=0; i<(int)_length; i++)
|
for(int i=0; i<(int)_length; i++)
|
||||||
snprintf(&tmp[i*2], (_length-i)*2+1, "%02x", _data[i]);
|
sprintf(&tmp[i*2], "%02x", _data[i]);
|
||||||
|
|
||||||
tmp[_length*2] = 0;
|
tmp[_length*2] = 0;
|
||||||
|
|
||||||
std::string res = tmp;
|
std::string res = tmp;
|
||||||
delete[] tmp;
|
delete[] tmp;
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ByteArray::append(const unsigned char* data, unsigned int length)
|
void ByteArray::append(const unsigned char* data, unsigned int length)
|
||||||
{
|
{
|
||||||
if (!length)
|
if (!length)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
unsigned int oldLength = _length;
|
||||||
|
|
||||||
unsigned int oldLength = _length;
|
resize(_length+length, true);
|
||||||
|
|
||||||
resize(_length+length, true);
|
memcpy(&_data[oldLength], data, length);
|
||||||
|
|
||||||
memcpy(&_data[oldLength], data, length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ByteArray::append(unsigned char c) { append(&c, 1);}
|
void ByteArray::append(unsigned char c) { append(&c, 1);}
|
||||||
void ByteArray::append(const char* str) { append((const unsigned char*)str, strlen(str));}
|
void ByteArray::append(const char* str) { append((const unsigned char*)str, strlen(str));}
|
||||||
void ByteArray::append(const std::string& str) { append((const unsigned char*)str.c_str(), str.length()); }
|
void ByteArray::append(const std::string& str) { append((const unsigned char*)str.c_str(), str.length()); }
|
||||||
|
|
||||||
void ByteArray::resize(unsigned length, bool keepData)
|
void ByteArray::resize(unsigned length, bool keepData)
|
||||||
{
|
{
|
||||||
if (length == _length)
|
if (length == _length)
|
||||||
return;
|
return;
|
||||||
else if (length < _length)
|
else if (length < _length)
|
||||||
_length = length ; // Don't touch data
|
_length = length ; // Don't touch data
|
||||||
else // New size >
|
else // New size >
|
||||||
{
|
{
|
||||||
unsigned char* newData;
|
unsigned char* newData;
|
||||||
|
|
||||||
if (_useMalloc)
|
if (_useMalloc)
|
||||||
newData = (unsigned char*)malloc(_length+length);
|
newData = (unsigned char*)malloc(_length+length);
|
||||||
else
|
else
|
||||||
newData = new unsigned char[_length+length];
|
newData = new unsigned char[_length+length];
|
||||||
|
|
||||||
if (keepData)
|
if (keepData)
|
||||||
memcpy(newData, _data, _length);
|
memcpy(newData, _data, _length);
|
||||||
|
|
||||||
|
delRef();
|
||||||
|
|
||||||
delRef();
|
_length = length;
|
||||||
|
_data = newData;
|
||||||
_length = length;
|
|
||||||
_data = newData;
|
addRef();
|
||||||
|
}
|
||||||
addRef();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
359
src/device.cpp
359
src/device.cpp
|
|
@ -29,23 +29,13 @@
|
||||||
#include <libgourou_log.h>
|
#include <libgourou_log.h>
|
||||||
#include <device.h>
|
#include <device.h>
|
||||||
|
|
||||||
#include <string.h>
|
// From https://stackoverflow.com/questions/1779715/how-to-get-mac-address-of-your-machine-using-a-c-program/35242525
|
||||||
#if defined(__linux__) || defined(linux) || defined(__linux)
|
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#elif (defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
|
#include <string.h>
|
||||||
|| defined(__bsdi__) || defined(__DragonFly__) || defined(__APPLE__))
|
|
||||||
#include <ifaddrs.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <net/if_dl.h>
|
|
||||||
|
|
||||||
#define BSD_HEADERS 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__linux__) || defined(linux) || defined(__linux)
|
|
||||||
// From https://stackoverflow.com/questions/1779715/how-to-get-mac-address-of-your-machine-using-a-c-program/35242525
|
|
||||||
int get_mac_address(unsigned char* mac_address)
|
int get_mac_address(unsigned char* mac_address)
|
||||||
{
|
{
|
||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
|
|
@ -78,275 +68,238 @@ int get_mac_address(unsigned char* mac_address)
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
memcpy(mac_address, ifr.ifr_hwaddr.sa_data, 6);
|
memcpy(mac_address, ifr.ifr_hwaddr.sa_data, 6);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#elif BSD_HEADERS
|
|
||||||
// https://stackoverflow.com/a/3978293
|
|
||||||
int get_mac_address(unsigned char* mac_address, const char* if_name = "en0")
|
|
||||||
{
|
|
||||||
ifaddrs* iflist;
|
|
||||||
int found = 0;
|
|
||||||
if (getifaddrs(&iflist) == 0) {
|
|
||||||
for (ifaddrs* cur = iflist; cur; cur = cur->ifa_next) {
|
|
||||||
if ((cur->ifa_addr->sa_family == AF_LINK) &&
|
|
||||||
(strcmp(cur->ifa_name, if_name) == 0) &&
|
|
||||||
cur->ifa_addr) {
|
|
||||||
sockaddr_dl* sdl = (sockaddr_dl*)cur->ifa_addr;
|
|
||||||
memcpy(mac_address, LLADDR(sdl), sdl->sdl_alen);
|
|
||||||
found = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
freeifaddrs(iflist);
|
|
||||||
}
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
int get_mac_address(unsigned char* mac_address)
|
|
||||||
{
|
|
||||||
GOUROU_LOG(INFO, "get_mac_address() not implemented for your platform, using a static address");
|
|
||||||
|
|
||||||
mac_address[0] = 0x8D;
|
|
||||||
mac_address[1] = 0x70;
|
|
||||||
mac_address[2] = 0x13;
|
|
||||||
mac_address[3] = 0x8D;
|
|
||||||
mac_address[4] = 0x43;
|
|
||||||
mac_address[5] = 0x27;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#endif /* defined(__linux__) || defined(linux) || defined(__linux) */
|
|
||||||
|
|
||||||
|
|
||||||
namespace gourou
|
namespace gourou
|
||||||
{
|
{
|
||||||
Device::Device(DRMProcessor* processor):
|
Device::Device(DRMProcessor* processor):
|
||||||
processor(processor)
|
processor(processor)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Device::Device(DRMProcessor* processor, const std::string& deviceFile, const std::string& deviceKeyFile):
|
Device::Device(DRMProcessor* processor, const std::string& deviceFile, const std::string& deviceKeyFile):
|
||||||
processor(processor), deviceFile(deviceFile), deviceKeyFile(deviceKeyFile)
|
processor(processor), deviceFile(deviceFile), deviceKeyFile(deviceKeyFile)
|
||||||
{
|
{
|
||||||
parseDeviceKeyFile();
|
parseDeviceKeyFile();
|
||||||
parseDeviceFile();
|
parseDeviceFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SHA1(uid ":" username ":" macaddress ":" */
|
/* SHA1(uid ":" username ":" macaddress ":" */
|
||||||
std::string Device::makeSerial(bool random)
|
std::string Device::makeSerial(bool random)
|
||||||
{
|
{
|
||||||
unsigned char sha_out[SHA1_LEN];
|
unsigned char sha_out[SHA1_LEN];
|
||||||
DRMProcessorClient* client = processor->getClient();
|
DRMProcessorClient* client = processor->getClient();
|
||||||
|
|
||||||
|
if (!random)
|
||||||
|
{
|
||||||
|
uid_t uid = getuid();
|
||||||
|
struct passwd * passwd = getpwuid(uid);
|
||||||
|
// Default mac address in case of failure
|
||||||
|
unsigned char mac_address[6] = {0x01, 0x02, 0x03, 0x04, 0x05};
|
||||||
|
|
||||||
if (!random)
|
get_mac_address(mac_address);
|
||||||
{
|
|
||||||
uid_t uid = getuid();
|
|
||||||
struct passwd * passwd = getpwuid(uid);
|
|
||||||
// Default mac address in case of failure
|
|
||||||
unsigned char mac_address[6] = {0x01, 0x02, 0x03, 0x04, 0x05};
|
|
||||||
|
|
||||||
get_mac_address(mac_address);
|
int dataToHashLen = 10 /* UID */ + strlen(passwd->pw_name) + sizeof(mac_address)*2 /*mac address*/ + 1 /* \0 */;
|
||||||
|
dataToHashLen += 8; /* Separators */
|
||||||
|
unsigned char* dataToHash = new unsigned char[dataToHashLen];
|
||||||
|
dataToHashLen = snprintf((char*)dataToHash, dataToHashLen, "%d:%s:%02x:%02x:%02x:%02x:%02x:%02x:",
|
||||||
|
uid, passwd->pw_name,
|
||||||
|
mac_address[0], mac_address[1], mac_address[2],
|
||||||
|
mac_address[3], mac_address[4], mac_address[5]);
|
||||||
|
|
||||||
|
client->digest("SHA1", dataToHash, dataToHashLen+1, sha_out);
|
||||||
|
|
||||||
int dataToHashLen = 10 /* UID */ + strlen(passwd->pw_name) + sizeof(mac_address)*2 /*mac address*/ + 1 /* \0 */;
|
delete[] dataToHash;
|
||||||
dataToHashLen += 8; /* Separators */
|
}
|
||||||
unsigned char* dataToHash = new unsigned char[dataToHashLen];
|
else
|
||||||
dataToHashLen = snprintf((char*)dataToHash, dataToHashLen, "%d:%s:%02x:%02x:%02x:%02x:%02x:%02x:",
|
{
|
||||||
uid, passwd->pw_name,
|
client->randBytes(sha_out, sizeof(sha_out));
|
||||||
mac_address[0], mac_address[1], mac_address[2],
|
}
|
||||||
mac_address[3], mac_address[4], mac_address[5]);
|
|
||||||
|
|
||||||
client->digest("SHA1", dataToHash, dataToHashLen+1, sha_out);
|
std::string res = ByteArray((const char*)sha_out, DEVICE_SERIAL_LEN).toHex();
|
||||||
|
GOUROU_LOG(DEBUG, "Serial : " << res);
|
||||||
delete[] dataToHash;
|
return res;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
client->randBytes(sha_out, sizeof(sha_out));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string res = ByteArray((const char*)sha_out, DEVICE_SERIAL_LEN).toHex();
|
|
||||||
GOUROU_LOG(DEBUG, "Serial : " << res);
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* base64(SHA1 (serial + privateKey)) */
|
/* base64(SHA1 (serial + privateKey)) */
|
||||||
std::string Device::makeFingerprint(const std::string& serial)
|
std::string Device::makeFingerprint(const std::string& serial)
|
||||||
{
|
{
|
||||||
DRMProcessorClient* client = processor->getClient();
|
DRMProcessorClient* client = processor->getClient();
|
||||||
unsigned char sha_out[SHA1_LEN];
|
unsigned char sha_out[SHA1_LEN];
|
||||||
|
|
||||||
void* handler = client->createDigest("SHA1");
|
void* handler = client->createDigest("SHA1");
|
||||||
client->digestUpdate(handler, (unsigned char*) serial.c_str(), serial.length());
|
client->digestUpdate(handler, (unsigned char*) serial.c_str(), serial.length());
|
||||||
client->digestUpdate(handler, deviceKey, sizeof(deviceKey));
|
client->digestUpdate(handler, deviceKey, sizeof(deviceKey));
|
||||||
client->digestFinalize(handler, sha_out);
|
client->digestFinalize(handler, sha_out);
|
||||||
|
|
||||||
std::string res = ByteArray(sha_out, sizeof(sha_out)).toBase64();
|
std::string res = ByteArray(sha_out, sizeof(sha_out)).toBase64();
|
||||||
GOUROU_LOG(DEBUG, "Fingerprint : " << res);
|
GOUROU_LOG(DEBUG, "Fingerprint : " << res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::createDeviceFile(const std::string& hobbes, bool randomSerial)
|
void Device::createDeviceFile(const std::string& hobbes, bool randomSerial)
|
||||||
{
|
{
|
||||||
struct utsname sysname;
|
struct utsname sysname;
|
||||||
uname(&sysname);
|
uname(&sysname);
|
||||||
|
|
||||||
std::string serial = makeSerial(randomSerial);
|
std::string serial = makeSerial(randomSerial);
|
||||||
std::string fingerprint = makeFingerprint(serial);
|
std::string fingerprint = makeFingerprint(serial);
|
||||||
|
|
||||||
|
pugi::xml_document deviceDoc;
|
||||||
|
pugi::xml_node decl = deviceDoc.append_child(pugi::node_declaration);
|
||||||
|
decl.append_attribute("version") = "1.0";
|
||||||
|
|
||||||
|
pugi::xml_node root = deviceDoc.append_child("adept:deviceInfo");
|
||||||
|
root.append_attribute("xmlns:adept") = ADOBE_ADEPT_NS;
|
||||||
|
|
||||||
pugi::xml_document deviceDoc;
|
appendTextElem(root, "adept:deviceClass", "Desktop");
|
||||||
pugi::xml_node decl = deviceDoc.append_child(pugi::node_declaration);
|
appendTextElem(root, "adept:deviceSerial", serial);
|
||||||
decl.append_attribute("version") = "1.0";
|
appendTextElem(root, "adept:deviceName", sysname.nodename);
|
||||||
|
appendTextElem(root, "adept:deviceType", "standalone");
|
||||||
|
|
||||||
pugi::xml_node root = deviceDoc.append_child("adept:deviceInfo");
|
pugi::xml_node version = root.append_child("adept:version");
|
||||||
root.append_attribute("xmlns:adept") = ADOBE_ADEPT_NS;
|
version.append_attribute("name") = "hobbes";
|
||||||
|
version.append_attribute("value") = hobbes.c_str();
|
||||||
|
|
||||||
|
version = root.append_child("adept:version");
|
||||||
|
version.append_attribute("name") = "clientOS";
|
||||||
|
std::string os = std::string(sysname.sysname) + " " + std::string(sysname.release);
|
||||||
|
version.append_attribute("value") = os.c_str();
|
||||||
|
|
||||||
|
version = root.append_child("adept:version");
|
||||||
|
version.append_attribute("name") = "clientLocale";
|
||||||
|
version.append_attribute("value") = setlocale(LC_ALL, NULL);
|
||||||
|
|
||||||
appendTextElem(root, "adept:deviceClass", "Desktop");
|
appendTextElem(root, "adept:fingerprint", fingerprint);
|
||||||
appendTextElem(root, "adept:deviceSerial", serial);
|
|
||||||
appendTextElem(root, "adept:deviceName", sysname.nodename);
|
|
||||||
appendTextElem(root, "adept:deviceType", "standalone");
|
|
||||||
|
|
||||||
pugi::xml_node version = root.append_child("adept:version");
|
StringXMLWriter xmlWriter;
|
||||||
version.append_attribute("name") = "hobbes";
|
deviceDoc.save(xmlWriter, " ");
|
||||||
version.append_attribute("value") = hobbes.c_str();
|
|
||||||
|
|
||||||
version = root.append_child("adept:version");
|
GOUROU_LOG(DEBUG, "Create device file " << deviceFile);
|
||||||
version.append_attribute("name") = "clientOS";
|
|
||||||
std::string os = std::string(sysname.sysname) + " " + std::string(sysname.release);
|
|
||||||
version.append_attribute("value") = os.c_str();
|
|
||||||
|
|
||||||
version = root.append_child("adept:version");
|
writeFile(deviceFile, xmlWriter.getResult());
|
||||||
version.append_attribute("name") = "clientLocale";
|
|
||||||
version.append_attribute("value") = setlocale(LC_ALL, NULL);
|
|
||||||
|
|
||||||
appendTextElem(root, "adept:fingerprint", fingerprint);
|
|
||||||
|
|
||||||
StringXMLWriter xmlWriter;
|
|
||||||
deviceDoc.save(xmlWriter, " ");
|
|
||||||
|
|
||||||
GOUROU_LOG(DEBUG, "Create device file " << deviceFile);
|
|
||||||
|
|
||||||
writeFile(deviceFile, xmlWriter.getResult());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::createDeviceKeyFile()
|
void Device::createDeviceKeyFile()
|
||||||
{
|
{
|
||||||
unsigned char key[DEVICE_KEY_SIZE];
|
unsigned char key[DEVICE_KEY_SIZE];
|
||||||
|
|
||||||
GOUROU_LOG(DEBUG, "Create device key file " << deviceKeyFile);
|
GOUROU_LOG(DEBUG, "Create device key file " << deviceKeyFile);
|
||||||
|
|
||||||
processor->getClient()->randBytes(key, sizeof(key));
|
processor->getClient()->randBytes(key, sizeof(key));
|
||||||
|
|
||||||
writeFile(deviceKeyFile, key, sizeof(key));
|
writeFile(deviceKeyFile, key, sizeof(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
Device* Device::createDevice(DRMProcessor* processor, const std::string& dirName, const std::string& hobbes, bool randomSerial)
|
Device* Device::createDevice(DRMProcessor* processor, const std::string& dirName, const std::string& hobbes, bool randomSerial)
|
||||||
{
|
{
|
||||||
struct stat _stat;
|
struct stat _stat;
|
||||||
|
|
||||||
if (stat(dirName.c_str(), &_stat) != 0)
|
if (stat(dirName.c_str(), &_stat) != 0)
|
||||||
{
|
{
|
||||||
if (mkdir_p(dirName.c_str(), S_IRWXU))
|
if (mkdir_p(dirName.c_str(), S_IRWXU))
|
||||||
EXCEPTION(DEV_MKPATH, "Unable to create " << dirName)
|
EXCEPTION(DEV_MKPATH, "Unable to create " << dirName)
|
||||||
}
|
}
|
||||||
|
|
||||||
Device* device = new Device(processor);
|
Device* device = new Device(processor);
|
||||||
|
|
||||||
device->deviceFile = dirName + "/device.xml";
|
device->deviceFile = dirName + "/device.xml";
|
||||||
device->deviceKeyFile = dirName + "/devicesalt";
|
device->deviceKeyFile = dirName + "/devicesalt";
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
device->parseDeviceKeyFile();
|
device->parseDeviceKeyFile();
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
device->createDeviceKeyFile();
|
device->createDeviceKeyFile();
|
||||||
device->parseDeviceKeyFile();
|
device->parseDeviceKeyFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
device->parseDeviceFile();
|
device->parseDeviceFile();
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
device->createDeviceFile(hobbes, randomSerial);
|
device->createDeviceFile(hobbes, randomSerial);
|
||||||
device->parseDeviceFile();
|
device->parseDeviceFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsigned char* Device::getDeviceKey()
|
const unsigned char* Device::getDeviceKey()
|
||||||
{
|
{
|
||||||
return deviceKey;
|
return deviceKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::parseDeviceFile()
|
void Device::parseDeviceFile()
|
||||||
{
|
{
|
||||||
pugi::xml_document doc;
|
pugi::xml_document doc;
|
||||||
|
|
||||||
if (!doc.load_file(deviceFile.c_str()))
|
if (!doc.load_file(deviceFile.c_str()))
|
||||||
EXCEPTION(DEV_INVALID_DEVICE_FILE, "Invalid device file");
|
EXCEPTION(DEV_INVALID_DEVICE_FILE, "Invalid device file");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
properties["deviceClass"] = gourou::extractTextElem(doc, "/adept:deviceInfo/adept:deviceClass");
|
properties["deviceClass"] = gourou::extractTextElem(doc, "/adept:deviceInfo/adept:deviceClass");
|
||||||
properties["deviceSerial"] = gourou::extractTextElem(doc, "/adept:deviceInfo/adept:deviceSerial");
|
properties["deviceSerial"] = gourou::extractTextElem(doc, "/adept:deviceInfo/adept:deviceSerial");
|
||||||
properties["deviceName"] = gourou::extractTextElem(doc, "/adept:deviceInfo/adept:deviceName");
|
properties["deviceName"] = gourou::extractTextElem(doc, "/adept:deviceInfo/adept:deviceName");
|
||||||
properties["deviceType"] = gourou::extractTextElem(doc, "/adept:deviceInfo/adept:deviceType");
|
properties["deviceType"] = gourou::extractTextElem(doc, "/adept:deviceInfo/adept:deviceType");
|
||||||
properties["fingerprint"] = gourou::extractTextElem(doc, "/adept:deviceInfo/adept:fingerprint");
|
properties["fingerprint"] = gourou::extractTextElem(doc, "/adept:deviceInfo/adept:fingerprint");
|
||||||
|
|
||||||
pugi::xpath_node_set nodeSet = doc.select_nodes("/adept:deviceInfo/adept:version");
|
pugi::xpath_node_set nodeSet = doc.select_nodes("/adept:deviceInfo/adept:version");
|
||||||
|
|
||||||
for (pugi::xpath_node_set::const_iterator it = nodeSet.begin();
|
for (pugi::xpath_node_set::const_iterator it = nodeSet.begin();
|
||||||
it != nodeSet.end(); ++it)
|
it != nodeSet.end(); ++it)
|
||||||
{
|
{
|
||||||
pugi::xml_node node = it->node();
|
pugi::xml_node node = it->node();
|
||||||
pugi::xml_attribute name = node.attribute("name");
|
pugi::xml_attribute name = node.attribute("name");
|
||||||
pugi::xml_attribute value = node.attribute("value");
|
pugi::xml_attribute value = node.attribute("value");
|
||||||
|
|
||||||
properties[name.value()] = value.value();
|
properties[name.value()] = value.value();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (gourou::Exception& e)
|
catch (gourou::Exception& e)
|
||||||
{
|
{
|
||||||
EXCEPTION(DEV_INVALID_DEVICE_FILE, "Invalid device file");
|
EXCEPTION(DEV_INVALID_DEVICE_FILE, "Invalid device file");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::parseDeviceKeyFile()
|
void Device::parseDeviceKeyFile()
|
||||||
{
|
{
|
||||||
struct stat _stat;
|
struct stat _stat;
|
||||||
|
|
||||||
if (stat(deviceKeyFile.c_str(), &_stat) == 0 &&
|
if (stat(deviceKeyFile.c_str(), &_stat) == 0 &&
|
||||||
_stat.st_size == DEVICE_KEY_SIZE)
|
_stat.st_size == DEVICE_KEY_SIZE)
|
||||||
{
|
{
|
||||||
readFile(deviceKeyFile, deviceKey, sizeof(deviceKey));
|
readFile(deviceKeyFile, deviceKey, sizeof(deviceKey));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
EXCEPTION(DEV_INVALID_DEVICE_KEY_FILE, "Invalid device key file");
|
EXCEPTION(DEV_INVALID_DEVICE_KEY_FILE, "Invalid device key file");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Device::getProperty(const std::string& property, const std::string& _default)
|
std::string Device::getProperty(const std::string& property, const std::string& _default)
|
||||||
{
|
{
|
||||||
if (properties.find(property) == properties.end())
|
if (properties.find(property) == properties.end())
|
||||||
{
|
{
|
||||||
if (_default == "")
|
if (_default == "")
|
||||||
EXCEPTION(DEV_INVALID_DEV_PROPERTY, "Invalid property " << property);
|
EXCEPTION(DEV_INVALID_DEV_PROPERTY, "Invalid property " << property);
|
||||||
|
|
||||||
return _default;
|
return _default;
|
||||||
}
|
}
|
||||||
|
|
||||||
return properties[property];
|
return properties[property];
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Device::operator[](const std::string& property)
|
std::string Device::operator[](const std::string& property)
|
||||||
{
|
{
|
||||||
return getProperty(property);
|
return getProperty(property);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@
|
||||||
along with libgourou. If not, see <http://www.gnu.org/licenses/>.
|
along with libgourou. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <cctype>
|
|
||||||
#include <fulfillment_item.h>
|
#include <fulfillment_item.h>
|
||||||
#include <libgourou_common.h>
|
#include <libgourou_common.h>
|
||||||
#include "user.h"
|
#include "user.h"
|
||||||
|
|
@ -25,109 +24,105 @@
|
||||||
namespace gourou
|
namespace gourou
|
||||||
{
|
{
|
||||||
FulfillmentItem::FulfillmentItem(pugi::xml_document& doc, User* user)
|
FulfillmentItem::FulfillmentItem(pugi::xml_document& doc, User* user)
|
||||||
: fulfillDoc(), loanToken(0)
|
: fulfillDoc(), loanToken(0)
|
||||||
{
|
{
|
||||||
fulfillDoc.reset(doc); /* We must keep a copy */
|
fulfillDoc.reset(doc); /* We must keep a copy */
|
||||||
metadatas = fulfillDoc.select_node("//metadata").node();
|
metadatas = fulfillDoc.select_node("//metadata").node();
|
||||||
|
|
||||||
|
if (!metadatas)
|
||||||
|
EXCEPTION(FFI_INVALID_FULFILLMENT_DATA, "No metadata tag in document");
|
||||||
|
|
||||||
|
pugi::xml_node node = doc.select_node("/envelope/fulfillmentResult/resourceItemInfo/src").node();
|
||||||
|
downloadURL = node.first_child().value();
|
||||||
|
|
||||||
if (!metadatas)
|
if (downloadURL == "")
|
||||||
EXCEPTION(FFI_INVALID_FULFILLMENT_DATA, "No metadata tag in document");
|
EXCEPTION(FFI_INVALID_FULFILLMENT_DATA, "No download URL in document");
|
||||||
|
|
||||||
|
node = doc.select_node("/envelope/fulfillmentResult/resourceItemInfo/resource").node();
|
||||||
|
resource = node.first_child().value();
|
||||||
|
|
||||||
pugi::xml_node node = doc.select_node("/envelope/fulfillmentResult/resourceItemInfo/src").node();
|
if (resource == "")
|
||||||
downloadURL = node.first_child().value();
|
EXCEPTION(FFI_INVALID_FULFILLMENT_DATA, "No resource in document");
|
||||||
|
|
||||||
if (downloadURL == "")
|
pugi::xml_node licenseToken = doc.select_node("/envelope/fulfillmentResult/resourceItemInfo/licenseToken").node();
|
||||||
EXCEPTION(FFI_INVALID_FULFILLMENT_DATA, "No download URL in document");
|
|
||||||
|
|
||||||
node = doc.select_node("/envelope/fulfillmentResult/resourceItemInfo/resource").node();
|
if (!licenseToken)
|
||||||
resource = node.first_child().value();
|
EXCEPTION(FFI_INVALID_FULFILLMENT_DATA, "Any license token in document");
|
||||||
|
|
||||||
|
buildRights(licenseToken, user);
|
||||||
|
|
||||||
if (resource == "")
|
node = doc.select_node("/envelope/fulfillmentResult/returnable").node();
|
||||||
EXCEPTION(FFI_INVALID_FULFILLMENT_DATA, "No resource in document");
|
try
|
||||||
|
{
|
||||||
pugi::xml_node licenseToken = doc.select_node("/envelope/fulfillmentResult/resourceItemInfo/licenseToken").node();
|
if (node && node.first_child().value() == std::string("true"))
|
||||||
|
loanToken = new LoanToken(doc);
|
||||||
if (!licenseToken)
|
}
|
||||||
EXCEPTION(FFI_INVALID_FULFILLMENT_DATA, "Any license token in document");
|
catch(std::exception& e)
|
||||||
|
{
|
||||||
buildRights(licenseToken, user);
|
GOUROU_LOG(ERROR, "Book is returnable, but contains invalid loan token");
|
||||||
|
GOUROU_LOG(ERROR, e.what());
|
||||||
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()
|
FulfillmentItem::~FulfillmentItem()
|
||||||
{
|
{
|
||||||
if (loanToken) delete loanToken;
|
if (loanToken) delete loanToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FulfillmentItem::buildRights(const pugi::xml_node& licenseToken, User* user)
|
void FulfillmentItem::buildRights(const pugi::xml_node& licenseToken, User* user)
|
||||||
{
|
{
|
||||||
pugi::xml_node decl = rights.append_child(pugi::node_declaration);
|
pugi::xml_node decl = rights.append_child(pugi::node_declaration);
|
||||||
decl.append_attribute("version") = "1.0";
|
decl.append_attribute("version") = "1.0";
|
||||||
|
|
||||||
|
pugi::xml_node root = rights.append_child("adept:rights");
|
||||||
|
root.append_attribute("xmlns:adept") = ADOBE_ADEPT_NS;
|
||||||
|
|
||||||
|
pugi::xml_node newLicenseToken = root.append_copy(licenseToken);
|
||||||
|
if (!newLicenseToken.attribute("xmlns"))
|
||||||
|
newLicenseToken.append_attribute("xmlns") = ADOBE_ADEPT_NS;
|
||||||
|
|
||||||
pugi::xml_node root = rights.append_child("adept:rights");
|
pugi::xml_node licenseServiceInfo = root.append_child("adept:licenseServiceInfo");
|
||||||
root.append_attribute("xmlns:adept") = ADOBE_ADEPT_NS;
|
pugi::xml_node licenseURL = licenseToken.select_node("licenseURL").node();
|
||||||
|
licenseURL.set_name("adept:licenseURL");
|
||||||
pugi::xml_node newLicenseToken = root.append_copy(licenseToken);
|
licenseServiceInfo.append_copy(licenseURL);
|
||||||
if (!newLicenseToken.attribute("xmlns"))
|
pugi::xml_node certificate = licenseServiceInfo.append_child("adept:certificate");
|
||||||
newLicenseToken.append_attribute("xmlns") = ADOBE_ADEPT_NS;
|
std::string certificateValue = user->getLicenseServiceCertificate(licenseURL.first_child().value());
|
||||||
|
certificate.append_child(pugi::node_pcdata).set_value(certificateValue.c_str());
|
||||||
pugi::xml_node licenseServiceInfo = root.append_child("adept:licenseServiceInfo");
|
|
||||||
pugi::xml_node licenseURL = licenseToken.select_node("licenseURL").node();
|
|
||||||
licenseURL.set_name("adept:licenseURL");
|
|
||||||
licenseServiceInfo.append_copy(licenseURL);
|
|
||||||
pugi::xml_node certificate = licenseServiceInfo.append_child("adept:certificate");
|
|
||||||
std::string certificateValue = user->getLicenseServiceCertificate(licenseURL.first_child().value());
|
|
||||||
certificate.append_child(pugi::node_pcdata).set_value(certificateValue.c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string FulfillmentItem::getMetadata(std::string name)
|
std::string FulfillmentItem::getMetadata(std::string name)
|
||||||
{
|
{
|
||||||
// https://stackoverflow.com/questions/313970/how-to-convert-an-instance-of-stdstring-to-lower-case
|
// https://stackoverflow.com/questions/313970/how-to-convert-an-instance-of-stdstring-to-lower-case
|
||||||
#if __STDC_VERSION__ >= 201112L
|
std::transform(name.begin(), name.end(), name.begin(),
|
||||||
std::transform(name.begin(), name.end(), name.begin(),
|
[](unsigned char c){ return std::tolower(c); });
|
||||||
[](unsigned char c){ return std::tolower(c); });
|
name = std::string("dc:") + name;
|
||||||
#else
|
pugi::xpath_node path = metadatas.select_node(name.c_str());
|
||||||
std::transform(name.begin(), name.end(), name.begin(), tolower);
|
|
||||||
#endif
|
|
||||||
name = std::string("dc:") + name;
|
|
||||||
pugi::xpath_node path = metadatas.select_node(name.c_str());
|
|
||||||
|
|
||||||
if (!path)
|
if (!path)
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
return path.node().first_child().value();
|
return path.node().first_child().value();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string FulfillmentItem::getRights()
|
std::string FulfillmentItem::getRights()
|
||||||
{
|
{
|
||||||
StringXMLWriter xmlWriter;
|
StringXMLWriter xmlWriter;
|
||||||
rights.save(xmlWriter, " ");
|
rights.save(xmlWriter, " ");
|
||||||
return xmlWriter.getResult();
|
return xmlWriter.getResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string FulfillmentItem::getDownloadURL()
|
std::string FulfillmentItem::getDownloadURL()
|
||||||
{
|
{
|
||||||
return downloadURL;
|
return downloadURL;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string FulfillmentItem::getResource()
|
std::string FulfillmentItem::getResource()
|
||||||
{
|
{
|
||||||
return resource;
|
return resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
LoanToken* FulfillmentItem::getLoanToken()
|
LoanToken* FulfillmentItem::getLoanToken()
|
||||||
{
|
{
|
||||||
return loanToken;
|
return loanToken;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2208
src/libgourou.cpp
2208
src/libgourou.cpp
File diff suppressed because it is too large
Load diff
|
|
@ -24,57 +24,68 @@ namespace gourou
|
||||||
{
|
{
|
||||||
LoanToken::LoanToken(pugi::xml_document& doc)
|
LoanToken::LoanToken(pugi::xml_document& doc)
|
||||||
{
|
{
|
||||||
pugi::xml_node node = doc.select_node("/envelope/loanToken").node();
|
pugi::xml_node node = doc.select_node("/envelope/loanToken").node();
|
||||||
|
|
||||||
if (!node)
|
if (!node)
|
||||||
EXCEPTION(FFI_INVALID_LOAN_TOKEN, "No loanToken element in document");
|
EXCEPTION(FFI_INVALID_LOAN_TOKEN, "No loanToken element in document");
|
||||||
|
|
||||||
node = doc.select_node("/envelope/fulfillmentResult/fulfillment").node();
|
node = doc.select_node("/envelope/loanToken/loan").node();
|
||||||
|
|
||||||
if (node)
|
if (node)
|
||||||
properties["id"] = node.first_child().value();
|
properties["id"] = node.first_child().value();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
EXCEPTION(FFI_INVALID_LOAN_TOKEN, "No fulfillment element in document");
|
node = doc.select_node("/envelope/fulfillmentResult/resourceItemInfo/licenseToken/permissions/display/loan").node();
|
||||||
}
|
|
||||||
|
|
||||||
node = doc.select_node("/envelope/loanToken/operatorURL").node();
|
if (node)
|
||||||
|
properties["id"] = node.first_child().value();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node = doc.select_node("/envelope/fulfillmentResult/resourceItemInfo/licenseToken/permissions/play/loan").node();
|
||||||
|
if (node)
|
||||||
|
properties["id"] = node.first_child().value();
|
||||||
|
else
|
||||||
|
EXCEPTION(FFI_INVALID_LOAN_TOKEN, "No loanToken/loan element in document");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!node)
|
node = doc.select_node("/envelope/loanToken/operatorURL").node();
|
||||||
EXCEPTION(FFI_INVALID_LOAN_TOKEN, "No loanToken/operatorURL element in document");
|
|
||||||
|
|
||||||
properties["operatorURL"] = node.first_child().value();
|
if (!node)
|
||||||
|
EXCEPTION(FFI_INVALID_LOAN_TOKEN, "No loanToken/operatorURL element in document");
|
||||||
|
|
||||||
node = doc.select_node("/envelope/fulfillmentResult/resourceItemInfo/licenseToken/permissions/display/until").node();
|
properties["operatorURL"] = node.first_child().value();
|
||||||
|
|
||||||
if (node)
|
node = doc.select_node("/envelope/fulfillmentResult/resourceItemInfo/licenseToken/permissions/display/until").node();
|
||||||
properties["validity"] = node.first_child().value();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
node = doc.select_node("/envelope/fulfillmentResult/resourceItemInfo/licenseToken/permissions/play/until").node();
|
|
||||||
|
|
||||||
if (node)
|
if (node)
|
||||||
properties["validity"] = node.first_child().value();
|
properties["validity"] = node.first_child().value();
|
||||||
else
|
else
|
||||||
EXCEPTION(FFI_INVALID_LOAN_TOKEN, "No loanToken/operatorURL element in document");
|
{
|
||||||
}
|
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)
|
std::string LoanToken::getProperty(const std::string& property, const std::string& _default)
|
||||||
{
|
{
|
||||||
if (properties.find(property) == properties.end())
|
if (properties.find(property) == properties.end())
|
||||||
{
|
{
|
||||||
if (_default == "")
|
if (_default == "")
|
||||||
EXCEPTION(GOUROU_INVALID_PROPERTY, "Invalid property " << property);
|
EXCEPTION(GOUROU_INVALID_PROPERTY, "Invalid property " << property);
|
||||||
|
|
||||||
return _default;
|
return _default;
|
||||||
}
|
}
|
||||||
|
|
||||||
return properties[property];
|
return properties[property];
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string LoanToken::operator[](const std::string& property)
|
std::string LoanToken::operator[](const std::string& property)
|
||||||
{
|
{
|
||||||
return getProperty(property);
|
return getProperty(property);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1
src/pugixml.cpp
Symbolic link
1
src/pugixml.cpp
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
../lib/pugixml/src/pugixml.cpp
|
||||||
282
src/user.cpp
282
src/user.cpp
|
|
@ -24,60 +24,60 @@
|
||||||
|
|
||||||
namespace gourou {
|
namespace gourou {
|
||||||
User::User(DRMProcessor* processor):processor(processor) {}
|
User::User(DRMProcessor* processor):processor(processor) {}
|
||||||
|
|
||||||
User::User(DRMProcessor* processor, const std::string& activationFile):
|
User::User(DRMProcessor* processor, const std::string& activationFile):
|
||||||
processor(processor), activationFile(activationFile)
|
processor(processor), activationFile(activationFile)
|
||||||
{
|
{
|
||||||
parseActivationFile();
|
parseActivationFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
void User::parseActivationFile(bool throwOnNull)
|
void User::parseActivationFile(bool throwOnNull)
|
||||||
{
|
{
|
||||||
GOUROU_LOG(DEBUG, "Parse activation file " << activationFile);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
if (!activationDoc.load_file(activationFile.c_str()))
|
try
|
||||||
{
|
{
|
||||||
if (throwOnNull)
|
pkcs12 = gourou::extractTextElem(activationDoc, "//adept:pkcs12", throwOnNull);
|
||||||
EXCEPTION(USER_INVALID_ACTIVATION_FILE, "Invalid activation file");
|
uuid = gourou::extractTextElem(activationDoc, "//adept:user", throwOnNull);
|
||||||
return;
|
deviceUUID = gourou::extractTextElem(activationDoc, "//device", throwOnNull);
|
||||||
}
|
deviceFingerprint = gourou::extractTextElem(activationDoc, "//fingerprint", throwOnNull);
|
||||||
|
authenticationCertificate = gourou::extractTextElem(activationDoc, "//adept:authenticationCertificate", throwOnNull);
|
||||||
|
privateLicenseKey = gourou::extractTextElem(activationDoc, "//adept:privateLicenseKey", throwOnNull);
|
||||||
|
|
||||||
try
|
pugi::xpath_node xpath_node = activationDoc.select_node("//adept:username");
|
||||||
{
|
if (xpath_node)
|
||||||
pkcs12 = gourou::extractTextElem(activationDoc, "//adept:pkcs12", throwOnNull);
|
loginMethod = xpath_node.node().attribute("method").value();
|
||||||
uuid = gourou::extractTextElem(activationDoc, "//adept:user", throwOnNull);
|
else
|
||||||
deviceUUID = gourou::extractTextElem(activationDoc, "//device", throwOnNull);
|
{
|
||||||
deviceFingerprint = gourou::extractTextElem(activationDoc, "//fingerprint", throwOnNull);
|
if (throwOnNull)
|
||||||
authenticationCertificate = gourou::extractTextElem(activationDoc, "//adept:authenticationCertificate", throwOnNull);
|
EXCEPTION(USER_INVALID_ACTIVATION_FILE, "Invalid activation file");
|
||||||
privateLicenseKey = gourou::extractTextElem(activationDoc, "//adept:privateLicenseKey", throwOnNull);
|
}
|
||||||
|
|
||||||
pugi::xpath_node xpath_node = activationDoc.select_node("//adept:username");
|
if (loginMethod == "anonymous")
|
||||||
if (xpath_node)
|
username = "anonymous";
|
||||||
loginMethod = xpath_node.node().attribute("method").value();
|
else
|
||||||
else
|
username = gourou::extractTextElem(activationDoc, "//adept:username", throwOnNull);
|
||||||
{
|
|
||||||
if (throwOnNull)
|
pugi::xpath_node_set nodeSet = activationDoc.select_nodes("//adept:licenseServices/adept:licenseServiceInfo");
|
||||||
EXCEPTION(USER_INVALID_ACTIVATION_FILE, "Invalid activation file");
|
for (pugi::xpath_node_set::const_iterator it = nodeSet.begin();
|
||||||
}
|
it != nodeSet.end(); ++it)
|
||||||
|
{
|
||||||
if (loginMethod == "anonymous")
|
std::string url = gourou::extractTextElem(it->node(), "adept:licenseURL");
|
||||||
username = "anonymous";
|
std::string certificate = gourou::extractTextElem(it->node(), "adept:certificate");
|
||||||
else
|
licenseServiceCertificates[url] = certificate;
|
||||||
username = gourou::extractTextElem(activationDoc, "//adept:username", throwOnNull);
|
}
|
||||||
|
}
|
||||||
pugi::xpath_node_set nodeSet = activationDoc.select_nodes("//adept:licenseServices/adept:licenseServiceInfo");
|
catch(gourou::Exception& e)
|
||||||
for (pugi::xpath_node_set::const_iterator it = nodeSet.begin();
|
{
|
||||||
it != nodeSet.end(); ++it)
|
EXCEPTION(USER_INVALID_ACTIVATION_FILE, "Invalid activation file");
|
||||||
{
|
}
|
||||||
std::string url = gourou::extractTextElem(it->node(), "adept:licenseURL");
|
|
||||||
std::string certificate = gourou::extractTextElem(it->node(), "adept:certificate");
|
|
||||||
licenseServiceCertificates[url] = certificate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(gourou::Exception& e)
|
|
||||||
{
|
|
||||||
EXCEPTION(USER_INVALID_ACTIVATION_FILE, "Invalid activation file");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string& User::getUUID() { return uuid; }
|
std::string& User::getUUID() { return uuid; }
|
||||||
|
|
@ -88,136 +88,136 @@ namespace gourou {
|
||||||
std::string& User::getLoginMethod() { return loginMethod; }
|
std::string& User::getLoginMethod() { return loginMethod; }
|
||||||
std::string& User::getAuthenticationCertificate() { return authenticationCertificate; }
|
std::string& User::getAuthenticationCertificate() { return authenticationCertificate; }
|
||||||
std::string& User::getPrivateLicenseKey() { return privateLicenseKey; }
|
std::string& User::getPrivateLicenseKey() { return privateLicenseKey; }
|
||||||
|
|
||||||
void User::readActivation(pugi::xml_document& doc)
|
void User::readActivation(pugi::xml_document& doc)
|
||||||
{
|
{
|
||||||
if (!doc.load_file(activationFile.c_str()))
|
if (!doc.load_file(activationFile.c_str()))
|
||||||
EXCEPTION(USER_INVALID_ACTIVATION_FILE, "Invalid activation file");
|
EXCEPTION(USER_INVALID_ACTIVATION_FILE, "Invalid activation file");
|
||||||
}
|
}
|
||||||
|
|
||||||
void User::updateActivationFile(const char* data)
|
void User::updateActivationFile(const char* data)
|
||||||
{
|
{
|
||||||
GOUROU_LOG(INFO, "Update Activation file : " << std::endl << data);
|
GOUROU_LOG(INFO, "Update Activation file : " << std::endl << data);
|
||||||
|
|
||||||
writeFile(activationFile, (unsigned char*)data, strlen(data));
|
writeFile(activationFile, (unsigned char*)data, strlen(data));
|
||||||
|
|
||||||
parseActivationFile(false);
|
parseActivationFile(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void User::updateActivationFile(const pugi::xml_document& doc)
|
void User::updateActivationFile(const pugi::xml_document& doc)
|
||||||
{
|
{
|
||||||
StringXMLWriter xmlWriter;
|
StringXMLWriter xmlWriter;
|
||||||
doc.save(xmlWriter, " ");
|
doc.save(xmlWriter, " ");
|
||||||
updateActivationFile(xmlWriter.getResult().c_str());
|
updateActivationFile(xmlWriter.getResult().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string User::getProperty(const std::string property)
|
std::string User::getProperty(const std::string property)
|
||||||
{
|
{
|
||||||
pugi::xpath_node xpathRes = activationDoc.select_node(property.c_str());
|
pugi::xpath_node xpathRes = activationDoc.select_node(property.c_str());
|
||||||
if (!xpathRes)
|
if (!xpathRes)
|
||||||
EXCEPTION(USER_NO_PROPERTY, "Property " << property << " not found in activation.xml");
|
EXCEPTION(USER_NO_PROPERTY, "Property " << property << " not found in activation.xml");
|
||||||
|
|
||||||
std::string res = xpathRes.node().first_child().value();
|
std::string res = xpathRes.node().first_child().value();
|
||||||
return trim(res);
|
return trim(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
pugi::xpath_node_set User::getProperties(const std::string property)
|
pugi::xpath_node_set User::getProperties(const std::string property)
|
||||||
{
|
{
|
||||||
return activationDoc.select_nodes(property.c_str());
|
return activationDoc.select_nodes(property.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
User* User::createUser(DRMProcessor* processor, const std::string& dirName, const std::string& ACSServer)
|
User* User::createUser(DRMProcessor* processor, const std::string& dirName, const std::string& ACSServer)
|
||||||
{
|
{
|
||||||
struct stat _stat;
|
struct stat _stat;
|
||||||
|
|
||||||
if (stat(dirName.c_str(), &_stat) != 0)
|
if (stat(dirName.c_str(), &_stat) != 0)
|
||||||
{
|
{
|
||||||
if (mkdir_p(dirName.c_str(), S_IRWXU))
|
if (mkdir_p(dirName.c_str(), S_IRWXU))
|
||||||
EXCEPTION(USER_MKPATH, "Unable to create " << dirName)
|
EXCEPTION(USER_MKPATH, "Unable to create " << dirName)
|
||||||
}
|
}
|
||||||
|
|
||||||
User* user = new User(processor);
|
User* user = new User(processor);
|
||||||
bool doUpdate = false;
|
bool doUpdate = false;
|
||||||
|
|
||||||
|
user->activationFile = dirName + "/activation.xml";
|
||||||
|
user->parseActivationFile(false);
|
||||||
|
|
||||||
user->activationFile = dirName + "/activation.xml";
|
pugi::xpath_node nodeActivationInfo = user->activationDoc.select_node("activation_info");
|
||||||
user->parseActivationFile(false);
|
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");
|
||||||
|
|
||||||
pugi::xpath_node nodeActivationInfo = user->activationDoc.select_node("activation_info");
|
user->activationDoc.reset();
|
||||||
pugi::xpath_node nodeActivationServiceInfo = nodeActivationInfo.node().select_node("adept:activationServiceInfo");
|
|
||||||
pugi::xml_node activationInfo;
|
pugi::xml_node decl = user->activationDoc.append_child(pugi::node_declaration);
|
||||||
pugi::xml_node activationServiceInfo;
|
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());
|
||||||
|
|
||||||
if (nodeActivationInfo && nodeActivationServiceInfo)
|
pugi::xpath_node path = docActivationServiceInfo.select_node("//authURL");
|
||||||
{
|
appendTextElem(activationServiceInfo, "adept:authURL", path.node().first_child().value());
|
||||||
GOUROU_LOG(DEBUG, "Read previous activation configuration");
|
path = docActivationServiceInfo.select_node("//userInfoURL");
|
||||||
activationInfo = nodeActivationInfo.node();
|
appendTextElem(activationServiceInfo, "adept:userInfoURL", path.node().first_child().value());
|
||||||
activationServiceInfo = nodeActivationServiceInfo.node();
|
appendTextElem(activationServiceInfo, "adept:activationURL", ACSServer);
|
||||||
}
|
path = docActivationServiceInfo.select_node("//certificate");
|
||||||
else
|
appendTextElem(activationServiceInfo, "adept:certificate", path.node().first_child().value());
|
||||||
{
|
doUpdate = true;
|
||||||
GOUROU_LOG(DEBUG, "Create new activation");
|
}
|
||||||
|
|
||||||
|
pugi::xpath_node nodeAuthenticationCertificate = activationServiceInfo.select_node("adept:authenticationCertificate");
|
||||||
|
|
||||||
user->activationDoc.reset();
|
if (!nodeAuthenticationCertificate)
|
||||||
|
{
|
||||||
|
GOUROU_LOG(DEBUG, "Create new activation, authentication part");
|
||||||
|
|
||||||
pugi::xml_node decl = user->activationDoc.append_child(pugi::node_declaration);
|
pugi::xpath_node xpathRes = activationServiceInfo.select_node("adept:authURL");
|
||||||
decl.append_attribute("version") = "1.0";
|
if (!xpathRes)
|
||||||
activationInfo = user->activationDoc.append_child("activationInfo");
|
EXCEPTION(USER_NO_AUTHENTICATION_URL, "No authentication URL");
|
||||||
activationInfo.append_attribute("xmlns") = ADOBE_ADEPT_NS;
|
|
||||||
activationServiceInfo = activationInfo.append_child("adept:activationServiceInfo");
|
std::string authenticationURL = xpathRes.node().first_child().value();
|
||||||
activationServiceInfo.append_attribute("xmlns:adept") = ADOBE_ADEPT_NS;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
// Go to activation Service Info
|
if (doUpdate)
|
||||||
std::string activationURL = ACSServer + "/ActivationServiceInfo";
|
user->updateActivationFile(user->activationDoc);
|
||||||
ByteArray activationServiceInfoReply = processor->sendRequest(activationURL);
|
|
||||||
pugi::xml_document docActivationServiceInfo;
|
|
||||||
docActivationServiceInfo.load_buffer(activationServiceInfoReply.data(),
|
return user;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string User::getLicenseServiceCertificate(std::string url)
|
std::string User::getLicenseServiceCertificate(std::string url)
|
||||||
{
|
{
|
||||||
if (licenseServiceCertificates.count(trim(url)))
|
if (licenseServiceCertificates.count(trim(url)))
|
||||||
return licenseServiceCertificates[trim(url)];
|
return licenseServiceCertificates[trim(url)];
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,20 @@
|
||||||
BINDIR ?= /bin
|
|
||||||
MANDIR ?= /share/man
|
|
||||||
|
|
||||||
TARGET_BINARIES=acsmdownloader adept_activate adept_remove adept_loan_mgt
|
TARGETS=acsmdownloader adept_activate adept_remove adept_loan_mgt
|
||||||
TARGETS=$(TARGET_BINARIES) launcher
|
|
||||||
|
|
||||||
MAN_PAGES=acsmdownloader adept_activate adept_remove adept_loan_mgt
|
CXXFLAGS=-Wall -fPIC -I$(ROOT)/include -I$(ROOT)/lib/pugixml/src/
|
||||||
|
|
||||||
|
LDFLAGS=
|
||||||
|
|
||||||
|
ifneq ($(OPENSSL3),)
|
||||||
|
# OpenSSL 1.1.0 compat
|
||||||
|
CXXFLAGS += -DOPENSSL_API_COMPAT=0x10100000L
|
||||||
|
CXXFLAGS += -I/tmp/openssl3/usr/include/ -I/tmp/openssl3/usr/include/x86_64-linux-gnu
|
||||||
|
LDFLAGS += -L/tmp/openssl3/usr/lib/x86_64-linux-gnu -L/tmp/openssl3/usr/lib/x86_64-linux-gnu/ossl-modules
|
||||||
|
endif
|
||||||
|
|
||||||
CXXFLAGS=-Wall -fPIC -I$(ROOT)/include -fmacro-prefix-map=$(ROOT)/= -fdata-sections -ffunction-sections
|
|
||||||
|
|
||||||
STATIC_DEP=
|
STATIC_DEP=
|
||||||
# LDFLAGS += -Wl,--gc-sections
|
LDFLAGS += -L$(ROOT) -lcrypto -lzip -lz -lcurl
|
||||||
LDFLAGS += -L$(ROOT) -lcrypto -lzip -lz -lcurl -lpugixml
|
|
||||||
|
|
||||||
ifneq ($(STATIC_UTILS),)
|
ifneq ($(STATIC_UTILS),)
|
||||||
STATIC_DEP = $(ROOT)/libgourou.a
|
STATIC_DEP = $(ROOT)/libgourou.a
|
||||||
|
|
@ -19,7 +23,7 @@ LDFLAGS += -lgourou
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq ($(DEBUG),)
|
ifneq ($(DEBUG),)
|
||||||
CXXFLAGS += -ggdb -O0 -DDEBUG
|
CXXFLAGS += -ggdb -O0
|
||||||
else
|
else
|
||||||
CXXFLAGS += -O2
|
CXXFLAGS += -O2
|
||||||
endif
|
endif
|
||||||
|
|
@ -31,27 +35,23 @@ COMMON_LIB = utils.a
|
||||||
|
|
||||||
all: $(TARGETS)
|
all: $(TARGETS)
|
||||||
|
|
||||||
${COMMON_LIB}: $(COMMON_DEPS)
|
${COMMON_LIB}: ${COMMON_DEPS} ${STATIC_DEP}
|
||||||
$(CXX) $(CXXFLAGS) $(COMMON_DEPS) -c
|
$(CXX) $(CXXFLAGS) ${COMMON_DEPS} $(LDFLAGS) -c
|
||||||
$(AR) crs $@ $(COMMON_OBJECTS)
|
$(AR) crs $@ ${COMMON_OBJECTS} $(STATIC_DEP)
|
||||||
|
|
||||||
%: %.cpp $(COMMON_LIB) $(STATIC_DEP)
|
acsmdownloader: acsmdownloader.cpp ${COMMON_LIB}
|
||||||
$(CXX) $(CXXFLAGS) $^ $(STATIC_DEP) $(LDFLAGS) -o $@
|
$(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@
|
||||||
|
|
||||||
install: $(TARGET_BINARIES)
|
adept_activate: adept_activate.cpp ${COMMON_LIB}
|
||||||
install -d $(DESTDIR)$(PREFIX)/$(BINDIR)
|
$(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@
|
||||||
install -m 755 $(TARGET_BINARIES) $(DESTDIR)$(PREFIX)/$(BINDIR)
|
|
||||||
install -d $(DESTDIR)$(PREFIX)/$(MANDIR)/man1
|
|
||||||
install -m 644 man/*.1 $(DESTDIR)$(PREFIX)/$(MANDIR)/man1
|
|
||||||
|
|
||||||
uninstall:
|
adept_remove: adept_remove.cpp ${COMMON_LIB}
|
||||||
cd $(DESTDIR)$(PREFIX)/$(BINDIR)
|
$(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@
|
||||||
rm -f $(TARGET_BINARIES)
|
|
||||||
cd -
|
adept_loan_mgt: adept_loan_mgt.cpp ${COMMON_LIB}
|
||||||
cd $(DESTDIR)$(PREFIX)/$(MANDIR)/man1
|
$(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@
|
||||||
rm -f $(addsuffix .1,$(TARGET_BINARIES)
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(TARGETS) $(COMMON_LIB)
|
rm -f $(TARGETS)
|
||||||
|
|
||||||
ultraclean: clean
|
ultraclean: clean
|
||||||
|
|
|
||||||
|
|
@ -4,16 +4,16 @@
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
* Redistributions of source code must retain the above copyright
|
||||||
notice, this list of conditions and the following disclaimer.
|
notice, this list of conditions and the following disclaimer.
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions and the following disclaimer in the
|
notice, this list of conditions and the following disclaimer in the
|
||||||
documentation and/or other materials provided with the distribution.
|
documentation and/or other materials provided with the distribution.
|
||||||
* Neither the name of the copyright holder nor the
|
* Neither the name of the copyright holder nor the
|
||||||
names of its contributors may be used to endorse or promote products
|
names of its contributors may be used to endorse or promote products
|
||||||
derived from this software without specific prior written permission.
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
|
@ -46,164 +46,160 @@ static bool exportPrivateKey = false;
|
||||||
static const char* outputFile = 0;
|
static const char* outputFile = 0;
|
||||||
static const char* outputDir = 0;
|
static const char* outputDir = 0;
|
||||||
static bool resume = false;
|
static bool resume = false;
|
||||||
static bool notify = true;
|
|
||||||
|
|
||||||
|
|
||||||
class ACSMDownloader
|
class ACSMDownloader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
int run()
|
int run()
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
gourou::DRMProcessor processor(&client, deviceFile, activationFile, devicekeyFile);
|
gourou::DRMProcessor processor(&client, deviceFile, activationFile, devicekeyFile);
|
||||||
gourou::User* user = processor.getUser();
|
gourou::User* user = processor.getUser();
|
||||||
|
|
||||||
if (exportPrivateKey)
|
if (exportPrivateKey)
|
||||||
{
|
{
|
||||||
std::string filename;
|
std::string filename;
|
||||||
if (outputFile)
|
if (!outputFile)
|
||||||
filename = outputFile;
|
filename = std::string("Adobe_PrivateLicenseKey--") + user->getUsername() + ".der";
|
||||||
else
|
else
|
||||||
{
|
filename = outputFile;
|
||||||
filename = std::string("Adobe_PrivateLicenseKey--") + user->getUsername() + ".der";
|
|
||||||
|
if (outputDir)
|
||||||
|
{
|
||||||
|
if (!fileExists(outputDir))
|
||||||
|
mkpath(outputDir);
|
||||||
|
|
||||||
|
filename = std::string(outputDir) + "/" + filename;
|
||||||
|
}
|
||||||
|
|
||||||
if (outputDir)
|
processor.exportPrivateLicenseKey(filename);
|
||||||
filename = std::string(outputDir) + "/" + filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
createPath(filename.c_str());
|
std::cout << "Private license key exported to " << filename << std::endl;
|
||||||
|
}
|
||||||
processor.exportPrivateLicenseKey(filename);
|
else
|
||||||
|
{
|
||||||
|
gourou::FulfillmentItem* item = processor.fulfill(acsmFile);
|
||||||
|
|
||||||
std::cout << "Private license key exported to " << filename << std::endl;
|
std::string filename;
|
||||||
}
|
if (!outputFile)
|
||||||
else
|
{
|
||||||
{
|
filename = item->getMetadata("title");
|
||||||
gourou::FulfillmentItem* item = processor.fulfill(acsmFile, notify);
|
if (filename == "")
|
||||||
|
filename = "output";
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Remove invalid characters
|
||||||
|
std::replace(filename.begin(), filename.end(), '/', '_');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
filename = outputFile;
|
||||||
|
|
||||||
|
if (outputDir)
|
||||||
|
{
|
||||||
|
if (!fileExists(outputDir))
|
||||||
|
mkpath(outputDir);
|
||||||
|
|
||||||
std::string filename;
|
filename = std::string(outputDir) + "/" + filename;
|
||||||
if (outputFile)
|
}
|
||||||
filename = outputFile;
|
|
||||||
else
|
gourou::DRMProcessor::ITEM_TYPE type = processor.download(item, filename, resume);
|
||||||
{
|
|
||||||
filename = item->getMetadata("title");
|
|
||||||
if (filename == "")
|
|
||||||
filename = "output";
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Remove invalid characters
|
|
||||||
std::replace(filename.begin(), filename.end(), '/', '_');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outputDir)
|
if (!outputFile)
|
||||||
filename = std::string(outputDir) + "/" + filename;
|
{
|
||||||
}
|
std::string finalName = filename;
|
||||||
|
if (type == gourou::DRMProcessor::ITEM_TYPE::PDF)
|
||||||
createPath(filename.c_str());
|
finalName += ".pdf";
|
||||||
|
else
|
||||||
|
finalName += ".epub";
|
||||||
|
rename(filename.c_str(), finalName.c_str());
|
||||||
|
filename = finalName;
|
||||||
|
}
|
||||||
|
std::cout << "Created " << filename << std::endl;
|
||||||
|
|
||||||
gourou::DRMProcessor::ITEM_TYPE type = processor.download(item, filename, resume);
|
serializeLoanToken(item);
|
||||||
|
}
|
||||||
|
} catch(std::exception& e)
|
||||||
|
{
|
||||||
|
std::cout << e.what() << std::endl;
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (!outputFile)
|
return ret;
|
||||||
{
|
|
||||||
std::string finalName = filename;
|
|
||||||
if (type == gourou::DRMProcessor::ITEM_TYPE::PDF)
|
|
||||||
finalName += ".pdf";
|
|
||||||
else
|
|
||||||
finalName += ".epub";
|
|
||||||
rename(filename.c_str(), finalName.c_str());
|
|
||||||
filename = finalName;
|
|
||||||
}
|
|
||||||
std::cout << "Created " << filename << std::endl;
|
|
||||||
|
|
||||||
serializeLoanToken(item);
|
|
||||||
}
|
|
||||||
} catch(std::exception& e)
|
|
||||||
{
|
|
||||||
std::cout << e.what() << std::endl;
|
|
||||||
ret = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void serializeLoanToken(gourou::FulfillmentItem* item)
|
void serializeLoanToken(gourou::FulfillmentItem* item)
|
||||||
{
|
{
|
||||||
gourou::LoanToken* token = item->getLoanToken();
|
gourou::LoanToken* token = item->getLoanToken();
|
||||||
|
|
||||||
// No loan token available
|
// No loan token available
|
||||||
if (!token)
|
if (!token)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pugi::xml_document doc;
|
pugi::xml_document doc;
|
||||||
|
|
||||||
pugi::xml_node decl = doc.append_child(pugi::node_declaration);
|
pugi::xml_node decl = doc.append_child(pugi::node_declaration);
|
||||||
decl.append_attribute("version") = "1.0";
|
decl.append_attribute("version") = "1.0";
|
||||||
|
|
||||||
pugi::xml_node root = doc.append_child("loanToken");
|
pugi::xml_node root = doc.append_child("loanToken");
|
||||||
gourou::appendTextElem(root, "id", (*token)["id"]);
|
gourou::appendTextElem(root, "id", (*token)["id"]);
|
||||||
gourou::appendTextElem(root, "operatorURL", (*token)["operatorURL"]);
|
gourou::appendTextElem(root, "operatorURL", (*token)["operatorURL"]);
|
||||||
gourou::appendTextElem(root, "validity", (*token)["validity"]);
|
gourou::appendTextElem(root, "validity", (*token)["validity"]);
|
||||||
gourou::appendTextElem(root, "name", item->getMetadata("title"));
|
gourou::appendTextElem(root, "name", item->getMetadata("title"));
|
||||||
|
|
||||||
char * activationDir = strdup(deviceFile);
|
char * activationDir = strdup(deviceFile);
|
||||||
activationDir = dirname(activationDir);
|
activationDir = dirname(activationDir);
|
||||||
|
|
||||||
gourou::StringXMLWriter xmlWriter;
|
gourou::StringXMLWriter xmlWriter;
|
||||||
doc.save(xmlWriter, " ");
|
doc.save(xmlWriter, " ");
|
||||||
std::string xmlStr = xmlWriter.getResult();
|
std::string xmlStr = xmlWriter.getResult();
|
||||||
|
|
||||||
// Use first bytes of SHA1(id) as filename
|
// Use first bytes of SHA1(id) as filename
|
||||||
unsigned char sha1[gourou::SHA1_LEN];
|
unsigned char sha1[gourou::SHA1_LEN];
|
||||||
client.digest("SHA1", (unsigned char*)(*token)["id"].c_str(), (*token)["id"].size(), sha1);
|
client.digest("SHA1", (unsigned char*)(*token)["id"].c_str(), (*token)["id"].size(), sha1);
|
||||||
gourou::ByteArray tmp(sha1, sizeof(sha1));
|
gourou::ByteArray tmp(sha1, sizeof(sha1));
|
||||||
std::string filenameHex = tmp.toHex();
|
std::string filenameHex = tmp.toHex();
|
||||||
std::string filename(filenameHex.c_str(), ID_HASH_SIZE);
|
std::string filename(filenameHex.c_str(), ID_HASH_SIZE);
|
||||||
std::string fullPath = std::string(activationDir);
|
std::string fullPath = std::string(activationDir);
|
||||||
fullPath += std::string ("/") + std::string(LOANS_DIR);
|
fullPath += std::string ("/") + std::string(LOANS_DIR);
|
||||||
mkpath(fullPath.c_str());
|
mkpath(fullPath.c_str());
|
||||||
fullPath += filename + std::string(".xml");
|
fullPath += filename + std::string(".xml");
|
||||||
gourou::writeFile(fullPath, xmlStr);
|
gourou::writeFile(fullPath, xmlStr);
|
||||||
|
|
||||||
std::cout << "Loan token serialized into " << fullPath << std::endl;
|
std::cout << "Loan token serialized into " << fullPath << std::endl;
|
||||||
|
|
||||||
free(activationDir);
|
free(activationDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DRMProcessorClientImpl client;
|
DRMProcessorClientImpl client;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static void usage(const char* cmd)
|
static void usage(const char* cmd)
|
||||||
{
|
{
|
||||||
std::cout << basename((char*)cmd) << " download EPUB file from ACSM request file" << std::endl << std::endl;
|
std::cout << "Download EPUB file from ACSM request file" << std::endl;
|
||||||
std::cout << "Usage: " << basename((char*)cmd) << " [OPTIONS] file.acsm" << std::endl << std::endl;
|
|
||||||
std::cout << "Global Options:" << std::endl;
|
std::cout << "Usage: " << cmd << " [(-d|--device-file) device.xml] [(-a|--activation-file) activation.xml] [(-k|--device-key-file) devicesalt] [(-O|--output-dir) dir] [(-o|--output-file) output(.epub|.pdf|.der)] [(-r|--resume)] [(-v|--verbose)] [(-h|--help)] (-f|--acsm-file) file.acsm|(-e|--export-private-key)" << std::endl << std::endl;
|
||||||
std::cout << " " << "-O|--output-dir" << "\t" << "Optional output directory were to put result (default ./) (not compatible with -o)" << std::endl;
|
|
||||||
std::cout << " " << "-o|--output-file" << "\t" << "Optional output filename (default <title.(epub|pdf|der)>) (not compatible with -O)" << std::endl;
|
std::cout << " " << "-d|--device-file" << "\t" << "device.xml file from eReader" << std::endl;
|
||||||
std::cout << " " << "-f|--acsm-file" << "\t" << "Backward compatibility: ACSM request file for epub download" << std::endl;
|
std::cout << " " << "-a|--activation-file" << "\t" << "activation.xml file from eReader" << std::endl;
|
||||||
|
std::cout << " " << "-k|--device-key-file" << "\t" << "private device key file (eg devicesalt/devkey.bin) from eReader" << std::endl;
|
||||||
|
std::cout << " " << "-O|--output-dir" << "\t" << "Optional output directory were to put result (default ./)" << std::endl;
|
||||||
|
std::cout << " " << "-o|--output-file" << "\t" << "Optional output filename (default <title.(epub|pdf|der)>)" << std::endl;
|
||||||
|
std::cout << " " << "-f|--acsm-file" << "\t" << "ACSM request file for epub download" << std::endl;
|
||||||
std::cout << " " << "-e|--export-private-key"<< "\t" << "Export private key in DER format" << std::endl;
|
std::cout << " " << "-e|--export-private-key"<< "\t" << "Export private key in DER format" << std::endl;
|
||||||
std::cout << " " << "-r|--resume" << "\t\t" << "Try to resume download (in case of previous failure)" << std::endl;
|
std::cout << " " << "-r|--resume" << "\t\t" << "Try to resume download (in case of previous failure)" << std::endl;
|
||||||
std::cout << " " << "-N|--no-notify" << "\t\t" << "Don't notify server, even if requested" << std::endl;
|
|
||||||
std::cout << " " << "-v|--verbose" << "\t\t" << "Increase verbosity, can be set multiple times" << std::endl;
|
std::cout << " " << "-v|--verbose" << "\t\t" << "Increase verbosity, can be set multiple times" << std::endl;
|
||||||
std::cout << " " << "-V|--version" << "\t\t" << "Display libgourou version" << std::endl;
|
std::cout << " " << "-V|--version" << "\t\t" << "Display libgourou version" << std::endl;
|
||||||
std::cout << " " << "-h|--help" << "\t\t" << "This help" << std::endl;
|
std::cout << " " << "-h|--help" << "\t\t" << "This help" << std::endl;
|
||||||
|
|
||||||
std::cout << "ADEPT Options:" << std::endl;
|
|
||||||
std::cout << " " << "-D|--adept-directory" << "\t" << ".adept directory that must contains device.xml, activation.xml and devicesalt" << std::endl;
|
|
||||||
std::cout << " " << "-d|--device-file" << "\t" << "device.xml file from eReader" << std::endl;
|
|
||||||
std::cout << " " << "-a|--activation-file" << "\t" << "activation.xml file from eReader" << std::endl;
|
|
||||||
std::cout << " " << "-k|--device-key-file" << "\t" << "private device key file (eg devicesalt/devkey.bin) from eReader" << std::endl;
|
|
||||||
|
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
std::cout << "Device file, activation file and device key file are optionals. If not set, they are looked into :" << std::endl;
|
||||||
std::cout << "Environment:" << std::endl;
|
|
||||||
std::cout << "Device file, activation file and device key file are optionals. If not set, they are looked into :" << std::endl << std::endl;
|
|
||||||
std::cout << " * $ADEPT_DIR environment variable" << std::endl;
|
|
||||||
std::cout << " * /home/<user>/.config/adept" << std::endl;
|
|
||||||
std::cout << " * Current directory" << std::endl;
|
std::cout << " * Current directory" << std::endl;
|
||||||
std::cout << " * .adept" << std::endl;
|
std::cout << " * .adept" << std::endl;
|
||||||
std::cout << " * adobe-digital-editions directory" << std::endl;
|
std::cout << " * adobe-digital-editions directory" << std::endl;
|
||||||
|
|
@ -213,102 +209,79 @@ static void usage(const char* cmd)
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
int c, ret = -1;
|
int c, ret = -1;
|
||||||
std::string _deviceFile, _activationFile, _devicekeyFile;
|
|
||||||
|
|
||||||
const char** files[] = {&devicekeyFile, &deviceFile, &activationFile};
|
const char** files[] = {&devicekeyFile, &deviceFile, &activationFile};
|
||||||
int verbose = gourou::DRMProcessor::getLogLevel();
|
int verbose = gourou::DRMProcessor::getLogLevel();
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
static struct option long_options[] = {
|
static struct option long_options[] = {
|
||||||
{"adept-directory", required_argument, 0, 'D' },
|
{"device-file", required_argument, 0, 'd' },
|
||||||
{"device-file", required_argument, 0, 'd' },
|
{"activation-file", required_argument, 0, 'a' },
|
||||||
{"activation-file", required_argument, 0, 'a' },
|
{"device-key-file", required_argument, 0, 'k' },
|
||||||
{"device-key-file", required_argument, 0, 'k' },
|
{"output-dir", required_argument, 0, 'O' },
|
||||||
{"output-dir", required_argument, 0, 'O' },
|
{"output-file", required_argument, 0, 'o' },
|
||||||
{"output-file", required_argument, 0, 'o' },
|
{"acsm-file", required_argument, 0, 'f' },
|
||||||
{"acsm-file", required_argument, 0, 'f' },
|
{"export-private-key",no_argument, 0, 'e' },
|
||||||
{"export-private-key",no_argument, 0, 'e' },
|
{"resume", no_argument, 0, 'r' },
|
||||||
{"resume", no_argument, 0, 'r' },
|
{"verbose", no_argument, 0, 'v' },
|
||||||
{"no-notify", no_argument, 0, 'N' },
|
{"version", no_argument, 0, 'V' },
|
||||||
{"verbose", no_argument, 0, 'v' },
|
{"help", no_argument, 0, 'h' },
|
||||||
{"version", no_argument, 0, 'V' },
|
{0, 0, 0, 0 }
|
||||||
{"help", no_argument, 0, 'h' },
|
};
|
||||||
{0, 0, 0, 0 }
|
|
||||||
};
|
|
||||||
|
|
||||||
c = getopt_long(argc, argv, "D:d:a:k:O:o:f:erNvVh",
|
c = getopt_long(argc, argv, "d:a:k:O:o:f:ervVh",
|
||||||
long_options, &option_index);
|
long_options, &option_index);
|
||||||
if (c == -1)
|
if (c == -1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'D':
|
case 'd':
|
||||||
_deviceFile = std::string(optarg) + "/device.xml";
|
deviceFile = optarg;
|
||||||
_activationFile = std::string(optarg) + "/activation.xml";
|
break;
|
||||||
_devicekeyFile = std::string(optarg) + "/devicesalt";
|
case 'a':
|
||||||
deviceFile = _deviceFile.c_str();
|
activationFile = optarg;
|
||||||
activationFile = _activationFile.c_str();
|
break;
|
||||||
devicekeyFile = _devicekeyFile.c_str();
|
case 'k':
|
||||||
break;
|
devicekeyFile = optarg;
|
||||||
case 'd':
|
break;
|
||||||
deviceFile = optarg;
|
case 'f':
|
||||||
break;
|
acsmFile = optarg;
|
||||||
case 'a':
|
break;
|
||||||
activationFile = optarg;
|
case 'O':
|
||||||
break;
|
outputDir = optarg;
|
||||||
case 'k':
|
break;
|
||||||
devicekeyFile = optarg;
|
case 'o':
|
||||||
break;
|
outputFile = optarg;
|
||||||
case 'f':
|
break;
|
||||||
acsmFile = optarg;
|
case 'e':
|
||||||
break;
|
exportPrivateKey = true;
|
||||||
case 'O':
|
break;
|
||||||
outputDir = optarg;
|
case 'r':
|
||||||
break;
|
resume = true;
|
||||||
case 'o':
|
break;
|
||||||
outputFile = optarg;
|
case 'v':
|
||||||
break;
|
verbose++;
|
||||||
case 'e':
|
break;
|
||||||
exportPrivateKey = true;
|
case 'V':
|
||||||
break;
|
version();
|
||||||
case 'r':
|
return 0;
|
||||||
resume = true;
|
case 'h':
|
||||||
break;
|
usage(argv[0]);
|
||||||
case 'N':
|
return 0;
|
||||||
notify = false;
|
default:
|
||||||
break;
|
usage(argv[0]);
|
||||||
case 'v':
|
return -1;
|
||||||
verbose++;
|
}
|
||||||
break;
|
|
||||||
case 'V':
|
|
||||||
version();
|
|
||||||
return 0;
|
|
||||||
case 'h':
|
|
||||||
usage(argv[0]);
|
|
||||||
return 0;
|
|
||||||
default:
|
|
||||||
usage(argv[0]);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gourou::DRMProcessor::setLogLevel(verbose);
|
gourou::DRMProcessor::setLogLevel(verbose);
|
||||||
|
|
||||||
if (optind == argc-1)
|
|
||||||
acsmFile = argv[optind];
|
|
||||||
|
|
||||||
if ((!acsmFile && !exportPrivateKey) || (outputDir && !outputDir[0]) ||
|
if ((!acsmFile && !exportPrivateKey) || (outputDir && !outputDir[0]) ||
|
||||||
(outputFile && !outputFile[0]))
|
(outputFile && !outputFile[0]))
|
||||||
{
|
{
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
if (outputDir && outputFile)
|
|
||||||
{
|
|
||||||
std::cout << "Error : you cannot use both -o and -O" << std::endl;
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ACSMDownloader downloader;
|
ACSMDownloader downloader;
|
||||||
|
|
@ -318,44 +291,44 @@ int main(int argc, char** argv)
|
||||||
const char* orig;
|
const char* orig;
|
||||||
for (i=0; i<(int)ARRAY_SIZE(files); i++)
|
for (i=0; i<(int)ARRAY_SIZE(files); i++)
|
||||||
{
|
{
|
||||||
orig = *files[i];
|
orig = *files[i];
|
||||||
*files[i] = findFile(*files[i]);
|
*files[i] = findFile(*files[i]);
|
||||||
if (!*files[i])
|
if (!*files[i])
|
||||||
{
|
{
|
||||||
std::cout << "Error : " << orig << " doesn't exists, did you activate your device ?" << std::endl;
|
std::cout << "Error : " << orig << " doesn't exists, did you activate your device ?" << std::endl;
|
||||||
ret = -1;
|
ret = -1;
|
||||||
hasErrors = true;
|
hasErrors = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasErrors)
|
if (hasErrors)
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
if (exportPrivateKey)
|
if (exportPrivateKey)
|
||||||
{
|
{
|
||||||
if (acsmFile)
|
if (acsmFile)
|
||||||
{
|
{
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!pathExists(acsmFile))
|
if (!fileExists(acsmFile))
|
||||||
{
|
{
|
||||||
std::cout << "Error : " << acsmFile << " doesn't exists" << std::endl;
|
std::cout << "Error : " << acsmFile << " doesn't exists" << std::endl;
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = downloader.run();
|
ret = downloader.run();
|
||||||
|
|
||||||
end:
|
end:
|
||||||
for (i=0; i<(int)ARRAY_SIZE(files); i++)
|
for (i=0; i<(int)ARRAY_SIZE(files); i++)
|
||||||
{
|
{
|
||||||
if (*files[i])
|
if (*files[i])
|
||||||
free((void*)*files[i]);
|
free((void*)*files[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
||||||
|
|
@ -4,16 +4,16 @@
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
* Redistributions of source code must retain the above copyright
|
||||||
notice, this list of conditions and the following disclaimer.
|
notice, this list of conditions and the following disclaimer.
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions and the following disclaimer in the
|
notice, this list of conditions and the following disclaimer in the
|
||||||
documentation and/or other materials provided with the distribution.
|
documentation and/or other materials provided with the distribution.
|
||||||
* Neither the name of the copyright holder nor the
|
* Neither the name of the copyright holder nor the
|
||||||
names of its contributors may be used to endorse or promote products
|
names of its contributors may be used to endorse or promote products
|
||||||
derived from this software without specific prior written permission.
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
|
@ -31,7 +31,6 @@
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <libgen.h>
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
@ -64,72 +63,71 @@ static int getch() {
|
||||||
|
|
||||||
static std::string getpass(const char *prompt, bool show_asterisk=false)
|
static std::string getpass(const char *prompt, bool show_asterisk=false)
|
||||||
{
|
{
|
||||||
const char BACKSPACE=127;
|
const char BACKSPACE=127;
|
||||||
const char RETURN=10;
|
const char RETURN=10;
|
||||||
|
|
||||||
std::string password;
|
std::string password;
|
||||||
unsigned char ch=0;
|
unsigned char ch=0;
|
||||||
|
|
||||||
std::cout <<prompt;
|
std::cout <<prompt;
|
||||||
|
|
||||||
while((ch=getch())!= RETURN)
|
while((ch=getch())!= RETURN)
|
||||||
{
|
{
|
||||||
if(ch==BACKSPACE)
|
if(ch==BACKSPACE)
|
||||||
{
|
{
|
||||||
if(password.length()!=0)
|
if(password.length()!=0)
|
||||||
{
|
{
|
||||||
if(show_asterisk)
|
if(show_asterisk)
|
||||||
std::cout <<"\b \b";
|
std::cout <<"\b \b";
|
||||||
password.resize(password.length()-1);
|
password.resize(password.length()-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
password+=ch;
|
password+=ch;
|
||||||
if(show_asterisk)
|
if(show_asterisk)
|
||||||
std::cout <<'*';
|
std::cout <<'*';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::cout <<std::endl;
|
std::cout <<std::endl;
|
||||||
return password;
|
return password;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class ADEPTActivate
|
class ADEPTActivate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
int run()
|
int run()
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
DRMProcessorClientImpl client;
|
DRMProcessorClientImpl client;
|
||||||
gourou::DRMProcessor* processor = gourou::DRMProcessor::createDRMProcessor(
|
gourou::DRMProcessor* processor = gourou::DRMProcessor::createDRMProcessor(
|
||||||
&client, randomSerial, outputDir, hobbesVersion);
|
&client, randomSerial, outputDir, hobbesVersion);
|
||||||
|
|
||||||
processor->signIn(username, password);
|
processor->signIn(username, password);
|
||||||
processor->activateDevice();
|
processor->activateDevice();
|
||||||
|
|
||||||
std::cout << username << " fully signed and device activated in " << outputDir << std::endl;
|
std::cout << username << " fully signed and device activated in " << outputDir << std::endl;
|
||||||
} catch(std::exception& e)
|
} catch(std::exception& e)
|
||||||
{
|
{
|
||||||
std::cout << e.what() << std::endl;
|
std::cout << e.what() << std::endl;
|
||||||
ret = 1;
|
ret = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static void usage(const char* cmd)
|
static void usage(const char* cmd)
|
||||||
{
|
{
|
||||||
std::cout << basename((char*)cmd) << " create new device files used by ADEPT DRM" << std::endl << std::endl;
|
std::cout << "Create new device files used by ADEPT DRM" << std::endl;
|
||||||
|
|
||||||
std::cout << "Usage: " << basename((char*)cmd) << " OPTIONS" << std::endl << std::endl;
|
std::cout << "Usage: " << cmd << " (-a|--anonymous) | ( (-u|--username) username [(-p|--password) password] ) [(-O|--output-dir) dir] [(-r|--random-serial)] [(-v|--verbose)] [(-h|--help)]" << std::endl << std::endl;
|
||||||
|
|
||||||
std::cout << "Global Options:" << std::endl;
|
|
||||||
std::cout << " " << "-a|--anonymous" << "\t" << "Anonymous account, no need for username/password (Use it only with a DRM removal software)" << std::endl;
|
std::cout << " " << "-a|--anonymous" << "\t" << "Anonymous account, no need for username/password (Use it only with a DRM removal software)" << std::endl;
|
||||||
std::cout << " " << "-u|--username" << "\t\t" << "AdobeID username (ie adobe.com email account)" << std::endl;
|
std::cout << " " << "-u|--username" << "\t\t" << "AdobeID username (ie adobe.com email account)" << std::endl;
|
||||||
std::cout << " " << "-p|--password" << "\t\t" << "AdobeID password (asked if not set via command line) " << std::endl;
|
std::cout << " " << "-p|--password" << "\t\t" << "AdobeID password (asked if not set via command line) " << std::endl;
|
||||||
|
|
@ -160,129 +158,129 @@ int main(int argc, char** argv)
|
||||||
const char* _outputDir = outputDir;
|
const char* _outputDir = outputDir;
|
||||||
int verbose = gourou::DRMProcessor::getLogLevel();
|
int verbose = gourou::DRMProcessor::getLogLevel();
|
||||||
bool anonymous = false;
|
bool anonymous = false;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
static struct option long_options[] = {
|
static struct option long_options[] = {
|
||||||
{"anonymous", no_argument , 0, 'a' },
|
{"anonymous", no_argument , 0, 'a' },
|
||||||
{"username", required_argument, 0, 'u' },
|
{"username", required_argument, 0, 'u' },
|
||||||
{"password", required_argument, 0, 'p' },
|
{"password", required_argument, 0, 'p' },
|
||||||
{"output-dir", required_argument, 0, 'O' },
|
{"output-dir", required_argument, 0, 'O' },
|
||||||
{"hobbes-version",required_argument, 0, 'H' },
|
{"hobbes-version",required_argument, 0, 'H' },
|
||||||
{"random-serial", no_argument, 0, 'r' },
|
{"random-serial", no_argument, 0, 'r' },
|
||||||
{"verbose", no_argument, 0, 'v' },
|
{"verbose", no_argument, 0, 'v' },
|
||||||
{"version", no_argument, 0, 'V' },
|
{"version", no_argument, 0, 'V' },
|
||||||
{"help", no_argument, 0, 'h' },
|
{"help", no_argument, 0, 'h' },
|
||||||
{0, 0, 0, 0 }
|
{0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
c = getopt_long(argc, argv, "au:p:O:H:rvVh",
|
c = getopt_long(argc, argv, "au:p:O:H:rvVh",
|
||||||
long_options, &option_index);
|
long_options, &option_index);
|
||||||
if (c == -1)
|
if (c == -1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'a':
|
case 'a':
|
||||||
anonymous = true;
|
anonymous = true;
|
||||||
break;
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
username = optarg;
|
username = optarg;
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
password = optarg;
|
password = optarg;
|
||||||
break;
|
break;
|
||||||
case 'O':
|
case 'O':
|
||||||
_outputDir = optarg;
|
_outputDir = optarg;
|
||||||
break;
|
break;
|
||||||
case 'H':
|
case 'H':
|
||||||
hobbesVersion = optarg;
|
hobbesVersion = optarg;
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
verbose++;
|
verbose++;
|
||||||
break;
|
break;
|
||||||
case 'V':
|
case 'V':
|
||||||
version();
|
version();
|
||||||
return 0;
|
return 0;
|
||||||
case 'h':
|
case 'h':
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
return 0;
|
return 0;
|
||||||
case 'r':
|
case 'r':
|
||||||
randomSerial = true;
|
randomSerial = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gourou::DRMProcessor::setLogLevel(verbose);
|
gourou::DRMProcessor::setLogLevel(verbose);
|
||||||
|
|
||||||
if ((!username && !anonymous) ||
|
if ((!username && !anonymous) ||
|
||||||
(username && anonymous))
|
(username && anonymous))
|
||||||
{
|
{
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (anonymous)
|
if (anonymous)
|
||||||
{
|
{
|
||||||
username = "anonymous";
|
username = "anonymous";
|
||||||
password = "";
|
password = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_outputDir || _outputDir[0] == 0)
|
if (!_outputDir || _outputDir[0] == 0)
|
||||||
{
|
{
|
||||||
outputDir = strdup(gourou::DRMProcessor::getDefaultAdeptDir().c_str());
|
outputDir = strdup(abspath(DEFAULT_ADEPT_DIR));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Relative path
|
// Relative path
|
||||||
if (_outputDir[0] == '.' || _outputDir[0] != '/')
|
if (_outputDir[0] == '.' || _outputDir[0] != '/')
|
||||||
{
|
{
|
||||||
// realpath doesn't works if file/dir doesn't exists
|
// realpath doesn't works if file/dir doesn't exists
|
||||||
if (pathExists(_outputDir))
|
if (fileExists(_outputDir))
|
||||||
outputDir = strdup(realpath(_outputDir, 0));
|
outputDir = strdup(realpath(_outputDir, 0));
|
||||||
else
|
else
|
||||||
outputDir = strdup(abspath(_outputDir));
|
outputDir = strdup(abspath(_outputDir));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
outputDir = strdup(_outputDir);
|
outputDir = strdup(_outputDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string pass;
|
std::string pass;
|
||||||
if (pathExists(outputDir))
|
if (fileExists(outputDir))
|
||||||
{
|
{
|
||||||
int key;
|
int key;
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
std::cout << "!! Warning !! : " << outputDir << " already exists." << std::endl;
|
std::cout << "!! Warning !! : " << outputDir << " already exists." << std::endl;
|
||||||
std::cout << "All your data will be overwrite. Would you like to continue ? [y/N] " << std::flush ;
|
std::cout << "All your data will be overwrite. Would you like to continue ? [y/N] " << std::flush ;
|
||||||
key = getchar();
|
key = getchar();
|
||||||
if (key == 'n' || key == 'N' || key == '\n' || key == '\r')
|
if (key == 'n' || key == 'N' || key == '\n' || key == '\r')
|
||||||
goto end;
|
goto end;
|
||||||
if (key == 'y' || key == 'Y')
|
if (key == 'y' || key == 'Y')
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean STDIN buf
|
// Clean STDIN buf
|
||||||
while ((key = getchar()) != '\n')
|
while ((key = getchar()) != '\n')
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!password)
|
if (!password)
|
||||||
{
|
{
|
||||||
char prompt[128];
|
char prompt[128];
|
||||||
std::snprintf(prompt, sizeof(prompt), "Enter password for <%s> : ", username);
|
std::snprintf(prompt, sizeof(prompt), "Enter password for <%s> : ", username);
|
||||||
pass = getpass((const char*)prompt, false);
|
pass = getpass((const char*)prompt, false);
|
||||||
password = pass.c_str();
|
password = pass.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
ADEPTActivate activate;
|
ADEPTActivate activate;
|
||||||
|
|
||||||
ret = activate.run();
|
ret = activate.run();
|
||||||
|
|
||||||
end:
|
end:
|
||||||
free((void*)outputDir);
|
free((void*)outputDir);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,16 +4,16 @@
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
* Redistributions of source code must retain the above copyright
|
||||||
notice, this list of conditions and the following disclaimer.
|
notice, this list of conditions and the following disclaimer.
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions and the following disclaimer in the
|
notice, this list of conditions and the following disclaimer in the
|
||||||
documentation and/or other materials provided with the distribution.
|
documentation and/or other materials provided with the distribution.
|
||||||
* Neither the name of the copyright holder nor the
|
* Neither the name of the copyright holder nor the
|
||||||
names of its contributors may be used to endorse or promote products
|
names of its contributors may be used to endorse or promote products
|
||||||
derived from this software without specific prior written permission.
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
|
@ -45,14 +45,13 @@
|
||||||
|
|
||||||
#define MAX_SIZE_BOOK_NAME 30
|
#define MAX_SIZE_BOOK_NAME 30
|
||||||
|
|
||||||
static char* adeptDir = 0;
|
static char* activationDir = 0;
|
||||||
static const char* deviceFile = "device.xml";
|
static const char* deviceFile = "device.xml";
|
||||||
static const char* activationFile = "activation.xml";
|
static const char* activationFile = "activation.xml";
|
||||||
static const char* devicekeyFile = "devicesalt";
|
static const char* devicekeyFile = "devicesalt";
|
||||||
static bool list = false;
|
static bool list = false;
|
||||||
static const char* returnID = 0;
|
static const char* returnID = 0;
|
||||||
static const char* deleteID = 0;
|
static const char* deleteID = 0;
|
||||||
static bool notify = true;
|
|
||||||
|
|
||||||
struct Loan
|
struct Loan
|
||||||
{
|
{
|
||||||
|
|
@ -60,314 +59,295 @@ struct Loan
|
||||||
std::string operatorURL;
|
std::string operatorURL;
|
||||||
std::string validity;
|
std::string validity;
|
||||||
std::string bookName;
|
std::string bookName;
|
||||||
|
|
||||||
std::string path;
|
std::string path;
|
||||||
};
|
};
|
||||||
|
|
||||||
class LoanMGT
|
class LoanMGT
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
~LoanMGT()
|
~LoanMGT()
|
||||||
{
|
{
|
||||||
for (const auto& kv : loanedBooks)
|
for (const auto& kv : loanedBooks)
|
||||||
delete kv.second;
|
delete kv.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
int run()
|
int run()
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
DRMProcessorClientImpl client;
|
DRMProcessorClientImpl client;
|
||||||
gourou::DRMProcessor processor(&client, deviceFile, activationFile, devicekeyFile);
|
gourou::DRMProcessor processor(&client, deviceFile, activationFile, devicekeyFile);
|
||||||
|
|
||||||
loadLoanedBooks();
|
loadLoanedBooks();
|
||||||
|
|
||||||
if (list)
|
if (list)
|
||||||
displayLoanList();
|
displayLoanList();
|
||||||
else if (returnID)
|
else if (returnID)
|
||||||
returnBook(processor);
|
returnBook(processor);
|
||||||
else if (deleteID)
|
else if (deleteID)
|
||||||
deleteLoan();
|
deleteLoan();
|
||||||
} catch(std::exception& e)
|
} catch(std::exception& e)
|
||||||
{
|
{
|
||||||
std::cout << e.what() << std::endl;
|
std::cout << e.what() << std::endl;
|
||||||
ret = 1;
|
ret = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void loadLoanedBooks()
|
void loadLoanedBooks()
|
||||||
{
|
{
|
||||||
DIR *dp;
|
DIR *dp;
|
||||||
struct dirent *ep;
|
struct dirent *ep;
|
||||||
int entryLen;
|
int entryLen;
|
||||||
struct Loan* loan;
|
struct Loan* loan;
|
||||||
char * res;
|
char * res;
|
||||||
|
|
||||||
std::string loanDir = std::string(adeptDir) + std::string("/") + LOANS_DIR;
|
std::string loanDir = std::string(activationDir) + std::string("/") + LOANS_DIR;
|
||||||
|
|
||||||
if (!pathExists(loanDir.c_str()))
|
if (!fileExists(loanDir.c_str()))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
dp = opendir (loanDir.c_str());
|
dp = opendir (loanDir.c_str());
|
||||||
|
|
||||||
if(!dp)
|
if(!dp)
|
||||||
EXCEPTION(gourou::USER_INVALID_INPUT, "Cannot read directory " << loanDir);
|
EXCEPTION(gourou::USER_INVALID_INPUT, "Cannot read directory " << loanDir);
|
||||||
|
|
||||||
while ((ep = readdir (dp)))
|
while ((ep = readdir (dp)))
|
||||||
{
|
{
|
||||||
if (ep->d_type != DT_LNK &&
|
if (ep->d_type != DT_LNK &&
|
||||||
ep->d_type != DT_REG)
|
ep->d_type != DT_REG)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
entryLen = strlen(ep->d_name);
|
entryLen = strlen(ep->d_name);
|
||||||
|
|
||||||
if (entryLen <= 4 ||
|
if (entryLen <= 4 ||
|
||||||
ep->d_name[entryLen-4] != '.' ||
|
ep->d_name[entryLen-4] != '.' ||
|
||||||
ep->d_name[entryLen-3] != 'x' ||
|
ep->d_name[entryLen-3] != 'x' ||
|
||||||
ep->d_name[entryLen-2] != 'm' ||
|
ep->d_name[entryLen-2] != 'm' ||
|
||||||
ep->d_name[entryLen-1] != 'l')
|
ep->d_name[entryLen-1] != 'l')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
std::string id = std::string(ep->d_name, entryLen-4);
|
std::string id = std::string(ep->d_name, entryLen-4);
|
||||||
|
|
||||||
loan = new Loan;
|
loan = new Loan;
|
||||||
loan->path = loanDir + std::string("/") + ep->d_name;
|
loan->path = loanDir + std::string("/") + ep->d_name;
|
||||||
|
|
||||||
pugi::xml_document xmlDoc;
|
pugi::xml_document xmlDoc;
|
||||||
pugi::xml_node node;
|
pugi::xml_node node;
|
||||||
|
|
||||||
if (!xmlDoc.load_file(loan->path.c_str(), pugi::parse_ws_pcdata_single|pugi::parse_escapes, pugi::encoding_utf8))
|
if (!xmlDoc.load_file(loan->path.c_str(), pugi::parse_ws_pcdata_single|pugi::parse_escapes, pugi::encoding_utf8))
|
||||||
{
|
{
|
||||||
std::cout << "Invalid loan entry " << loan->path << std::endl;
|
std::cout << "Invalid loan entry " << loan->path << std::endl;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// id
|
// id
|
||||||
node = xmlDoc.select_node("//id").node();
|
node = xmlDoc.select_node("//id").node();
|
||||||
if (!node)
|
if (!node)
|
||||||
{
|
{
|
||||||
std::cout << "Invalid loan entry " << ep->d_name << ", no id element" << std::endl;
|
std::cout << "Invalid loan entry " << ep->d_name << ", no id element" << std::endl;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
loan->id = node.first_child().value();
|
loan->id = node.first_child().value();
|
||||||
|
|
||||||
// operatorURL
|
// operatorURL
|
||||||
node = xmlDoc.select_node("//operatorURL").node();
|
node = xmlDoc.select_node("//operatorURL").node();
|
||||||
if (!node)
|
if (!node)
|
||||||
{
|
{
|
||||||
std::cout << "Invalid loan entry " << ep->d_name << ", no operatorURL element" << std::endl;
|
std::cout << "Invalid loan entry " << ep->d_name << ", no operatorURL element" << std::endl;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
loan->operatorURL = node.first_child().value();
|
loan->operatorURL = node.first_child().value();
|
||||||
|
|
||||||
// validity
|
// validity
|
||||||
node = xmlDoc.select_node("//validity").node();
|
node = xmlDoc.select_node("//validity").node();
|
||||||
if (!node)
|
if (!node)
|
||||||
{
|
{
|
||||||
std::cout << "Invalid loan entry " << ep->d_name << ", no validity element" << std::endl;
|
std::cout << "Invalid loan entry " << ep->d_name << ", no validity element" << std::endl;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
loan->validity = node.first_child().value();
|
loan->validity = node.first_child().value();
|
||||||
|
|
||||||
// bookName
|
// bookName
|
||||||
node = xmlDoc.select_node("//name").node();
|
node = xmlDoc.select_node("//name").node();
|
||||||
if (!node)
|
if (!node)
|
||||||
{
|
{
|
||||||
std::cout << "Invalid loan entry " << ep->d_name << ", no name element" << std::endl;
|
std::cout << "Invalid loan entry " << ep->d_name << ", no name element" << std::endl;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
loan->bookName = node.first_child().value();
|
loan->bookName = node.first_child().value();
|
||||||
|
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
#ifdef __ANDROID__
|
res = strptime(loan->validity.c_str(), "%Y-%m-%dT%H:%M:%S%Z", &tm);
|
||||||
res = strptime(loan->validity.c_str(), "%Y-%m-%dT%H:%M:%S%z", &tm);
|
if (*res == 0)
|
||||||
#else
|
{
|
||||||
res = strptime(loan->validity.c_str(), "%Y-%m-%dT%H:%M:%S%Z", &tm);
|
if (mktime(&tm) <= time(NULL))
|
||||||
#endif
|
loan->validity = " (Expired)";
|
||||||
|
}
|
||||||
if (res != NULL && *res == 0)
|
else
|
||||||
{
|
{
|
||||||
if (mktime(&tm) <= time(NULL))
|
std::cout << "Unable to parse validity timestamp :" << loan->validity << std::endl;
|
||||||
loan->validity = " (Expired)";
|
loan->validity = " (Unknown)";
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
loanedBooks[id] = loan;
|
||||||
std::cout << "Unable to parse validity timestamp :" << loan->validity << std::endl;
|
continue;
|
||||||
loan->validity = " (Unknown)";
|
|
||||||
}
|
|
||||||
|
|
||||||
loanedBooks[id] = loan;
|
|
||||||
continue;
|
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (loan)
|
if (loan)
|
||||||
delete loan;
|
delete loan;
|
||||||
}
|
}
|
||||||
|
|
||||||
closedir (dp);
|
closedir (dp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void displayLoanList()
|
void displayLoanList()
|
||||||
{
|
{
|
||||||
if (!loanedBooks.size())
|
if (!loanedBooks.size())
|
||||||
{
|
{
|
||||||
std::cout << "No books loaned" << std::endl;
|
std::cout << "Any book loaned" << std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Loan* loan;
|
struct Loan* loan;
|
||||||
unsigned int maxSizeBookName=0;
|
unsigned int maxSizeBookName=0;
|
||||||
// Compute max size
|
// Compute max size
|
||||||
for (const auto& kv : loanedBooks)
|
for (const auto& kv : loanedBooks)
|
||||||
{
|
{
|
||||||
loan = kv.second;
|
loan = kv.second;
|
||||||
if (loan->bookName.size() > maxSizeBookName)
|
if (loan->bookName.size() > maxSizeBookName)
|
||||||
maxSizeBookName = loan->bookName.size();
|
maxSizeBookName = loan->bookName.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Manage empty names */
|
if (maxSizeBookName > MAX_SIZE_BOOK_NAME)
|
||||||
if (maxSizeBookName == 0)
|
maxSizeBookName = MAX_SIZE_BOOK_NAME;
|
||||||
maxSizeBookName = sizeof("No name ")-1;
|
else if ((maxSizeBookName % 2))
|
||||||
else if (maxSizeBookName < 4)
|
maxSizeBookName++;
|
||||||
maxSizeBookName = 4;
|
|
||||||
else if (maxSizeBookName > MAX_SIZE_BOOK_NAME)
|
|
||||||
maxSizeBookName = MAX_SIZE_BOOK_NAME;
|
|
||||||
else if ((maxSizeBookName % 2))
|
|
||||||
maxSizeBookName++;
|
|
||||||
|
|
||||||
// std::cout << " ID Book Expiration" << std::endl;
|
// std::cout << " ID Book Expiration" << std::endl;
|
||||||
// std::cout << "------------------------------" << std::endl;
|
// std::cout << "------------------------------" << std::endl;
|
||||||
|
|
||||||
int fillID, fillBookName, fillExpiration=(20 - 10)/2;
|
int fillID, fillBookName, fillExpiration=(20 - 10)/2;
|
||||||
|
|
||||||
fillID = (ID_HASH_SIZE - 2) / 2;
|
fillID = (ID_HASH_SIZE - 2) / 2;
|
||||||
fillBookName = (maxSizeBookName - 4) / 2;
|
fillBookName = (maxSizeBookName - 4) / 2;
|
||||||
|
|
||||||
std::cout.width (fillID);
|
std::cout.width (fillID);
|
||||||
std::cout << "";
|
std::cout << "";
|
||||||
std::cout << "ID" ;
|
std::cout << "ID" ;
|
||||||
std::cout.width (fillID);
|
std::cout.width (fillID);
|
||||||
std::cout << "";
|
std::cout << "";
|
||||||
std::cout << " " ;
|
std::cout << " " ;
|
||||||
|
|
||||||
std::cout.width (fillBookName);
|
std::cout.width (fillBookName);
|
||||||
std::cout << "";
|
std::cout << "";
|
||||||
std::cout << "Book" ;
|
std::cout << "Book" ;
|
||||||
std::cout.width (fillBookName);
|
std::cout.width (fillBookName);
|
||||||
std::cout << "";
|
std::cout << "";
|
||||||
std::cout << " " ;
|
std::cout << " " ;
|
||||||
|
|
||||||
std::cout.width (fillExpiration);
|
std::cout.width (fillExpiration);
|
||||||
std::cout << "";
|
std::cout << "";
|
||||||
std::cout << "Expiration";
|
std::cout << "Exipration";
|
||||||
std::cout.width (fillExpiration);
|
std::cout.width (fillExpiration);
|
||||||
std::cout << "" << std::endl;
|
std::cout << "" << std::endl;
|
||||||
|
|
||||||
std::cout.fill ('-');
|
std::cout.fill ('-');
|
||||||
std::cout.width (ID_HASH_SIZE + 4 + maxSizeBookName + 4 + 20);
|
std::cout.width (ID_HASH_SIZE + 4 + maxSizeBookName + 4 + 20);
|
||||||
std::cout << "" << std::endl;
|
std::cout << "" << std::endl;
|
||||||
std::cout.fill (' ');
|
std::cout.fill (' ');
|
||||||
|
|
||||||
std::string bookName;
|
std::string bookName;
|
||||||
|
|
||||||
for (const auto& kv : loanedBooks)
|
for (const auto& kv : loanedBooks)
|
||||||
{
|
{
|
||||||
loan = kv.second;
|
loan = kv.second;
|
||||||
|
|
||||||
std::cout << kv.first;
|
std::cout << kv.first;
|
||||||
std::cout << " ";
|
std::cout << " ";
|
||||||
|
|
||||||
if (loan->bookName.size() == 0)
|
if (loan->bookName.size() > MAX_SIZE_BOOK_NAME)
|
||||||
bookName = std::string("No name ");
|
bookName = std::string(loan->bookName.c_str(), MAX_SIZE_BOOK_NAME);
|
||||||
else if (loan->bookName.size() > MAX_SIZE_BOOK_NAME)
|
else
|
||||||
bookName = std::string(loan->bookName.c_str(), MAX_SIZE_BOOK_NAME);
|
bookName = loan->bookName;
|
||||||
else
|
|
||||||
bookName = loan->bookName;
|
|
||||||
|
|
||||||
std::cout << bookName;
|
std::cout << bookName;
|
||||||
std::cout.width (maxSizeBookName - bookName.size());
|
std::cout.width (maxSizeBookName - bookName.size());
|
||||||
std::cout << "";
|
std::cout << "";
|
||||||
std::cout << " ";
|
std::cout << " ";
|
||||||
|
|
||||||
std::cout << loan->validity << std::endl;
|
std::cout << loan->validity << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void returnBook(gourou::DRMProcessor& processor)
|
void returnBook(gourou::DRMProcessor& processor)
|
||||||
{
|
{
|
||||||
struct Loan* loan = loanedBooks[std::string(returnID)];
|
struct Loan* loan = loanedBooks[std::string(returnID)];
|
||||||
|
|
||||||
if (!loan)
|
if (!loan)
|
||||||
{
|
{
|
||||||
std::cout << "Error : Loan " << returnID << " doesn't exists" << std::endl;
|
std::cout << "Error : Loan " << returnID << " doesn't exists" << std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
processor.returnLoan(loan->id, loan->operatorURL, notify);
|
processor.returnLoan(loan->id, loan->operatorURL);
|
||||||
|
|
||||||
deleteID = returnID;
|
deleteID = returnID;
|
||||||
if (deleteLoan(false))
|
if (deleteLoan(false))
|
||||||
{
|
{
|
||||||
std::cout << "Loan " << returnID << " successfully returned" << std::endl;
|
std::cout << "Loan " << returnID << " successfully returned" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deleteLoan(bool displayResult=true)
|
bool deleteLoan(bool displayResult=true)
|
||||||
{
|
{
|
||||||
struct Loan* loan = loanedBooks[std::string(deleteID)];
|
struct Loan* loan = loanedBooks[std::string(deleteID)];
|
||||||
|
|
||||||
if (!loan)
|
if (!loan)
|
||||||
{
|
{
|
||||||
std::cout << "Error : Loan " << deleteID << " doesn't exists" << std::endl;
|
std::cout << "Error : Loan " << deleteID << " doesn't exists" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlink(loan->path.c_str()))
|
if (unlink(loan->path.c_str()))
|
||||||
{
|
{
|
||||||
std::cout << "Error : Cannot delete " << loan->path << std::endl;
|
std::cout << "Error : Cannot delete " << loan->path << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (displayResult)
|
else if (displayResult)
|
||||||
{
|
{
|
||||||
std::cout << "Loan " << deleteID << " deleted" << std::endl;
|
std::cout << "Loan " << deleteID << " deleted" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, struct Loan*> loanedBooks;
|
std::map<std::string, struct Loan*> loanedBooks;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static void usage(const char* cmd)
|
static void usage(const char* cmd)
|
||||||
{
|
{
|
||||||
std::cout << basename((char*)cmd) << " manage loaned books" << std::endl << std::endl;
|
std::cout << "Manage loaned books" << std::endl;
|
||||||
|
|
||||||
std::cout << "Usage: " << basename((char*)cmd) << " [OPTIONS]" << std::endl << std::endl;
|
std::cout << "Usage: " << cmd << " [(-d|--activation-dir) dir] (-l|--list)|(-D|--delete loanID)|(-R|--delete loanID) [(-v|--verbose)] [(-h|--help)]" << std::endl << std::endl;
|
||||||
|
|
||||||
std::cout << "Global Options:" << std::endl;
|
std::cout << " " << "-d|--activation-dir" << "\t" << "Directory of device.xml/activation.xml and device key" << std::endl;
|
||||||
std::cout << " " << "-l|--list" << "\t\t" << "List all loaned books" << std::endl;
|
std::cout << " " << "-l|--list" << "\t\t" << "List all loaned books" << std::endl;
|
||||||
std::cout << " " << "-r|--return" << "\t\t" << "Return a loaned book" << std::endl;
|
std::cout << " " << "-r|--return" << "\t\t" << "Return a loaned book" << std::endl;
|
||||||
std::cout << " " << "-d|--delete" << "\t\t" << "Delete a loan entry without returning it" << std::endl;
|
std::cout << " " << "-D|--delete" << "\t\t" << "Delete a loan entry without returning it" << std::endl;
|
||||||
std::cout << " " << "-N|--no-notify" << "\t\t" << "Don't notify server, even if requested" << std::endl;
|
|
||||||
std::cout << " " << "-v|--verbose" << "\t\t" << "Increase verbosity, can be set multiple times" << std::endl;
|
std::cout << " " << "-v|--verbose" << "\t\t" << "Increase verbosity, can be set multiple times" << std::endl;
|
||||||
std::cout << " " << "-V|--version" << "\t\t" << "Display libgourou version" << std::endl;
|
std::cout << " " << "-V|--version" << "\t\t" << "Display libgourou version" << std::endl;
|
||||||
std::cout << " " << "-h|--help" << "\t\t" << "This help" << std::endl;
|
std::cout << " " << "-h|--help" << "\t\t" << "This help" << std::endl;
|
||||||
|
|
||||||
std::cout << "ADEPT Options:" << std::endl;
|
|
||||||
std::cout << " " << "-D|--adept-directory" << "\t" << ".adept directory that must contains device.xml, activation.xml and devicesalt" << std::endl;
|
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
std::cout << "Activation directory is optional. If not set, it's looked into :" << std::endl;
|
||||||
std::cout << "Environment:" << std::endl;
|
|
||||||
std::cout << "ADEPT directory is optional. If not set, it's looked into :" << std::endl;
|
|
||||||
std::cout << " * $ADEPT_DIR environment variable" << std::endl;
|
|
||||||
std::cout << " * /home/<user>/.config/adept" << std::endl;
|
|
||||||
std::cout << " * Current directory" << std::endl;
|
std::cout << " * Current directory" << std::endl;
|
||||||
std::cout << " * .adept" << std::endl;
|
std::cout << " * .adept" << std::endl;
|
||||||
std::cout << " * adobe-digital-editions directory" << std::endl;
|
std::cout << " * adobe-digital-editions directory" << std::endl;
|
||||||
|
|
@ -381,69 +361,65 @@ int main(int argc, char** argv)
|
||||||
const char** files[] = {&devicekeyFile, &deviceFile, &activationFile};
|
const char** files[] = {&devicekeyFile, &deviceFile, &activationFile};
|
||||||
int verbose = gourou::DRMProcessor::getLogLevel();
|
int verbose = gourou::DRMProcessor::getLogLevel();
|
||||||
int actions = 0;
|
int actions = 0;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
static struct option long_options[] = {
|
static struct option long_options[] = {
|
||||||
{"adept-directory", required_argument, 0, 'D' },
|
{"activation-dir", required_argument, 0, 'd' },
|
||||||
{"list", no_argument, 0, 'l' },
|
{"list", no_argument, 0, 'l' },
|
||||||
{"return", no_argument, 0, 'r' },
|
{"return", no_argument, 0, 'r' },
|
||||||
{"delete", no_argument, 0, 'd' },
|
{"delete", no_argument, 0, 'D' },
|
||||||
{"no-notify", no_argument, 0, 'N' },
|
{"verbose", no_argument, 0, 'v' },
|
||||||
{"verbose", no_argument, 0, 'v' },
|
{"version", no_argument, 0, 'V' },
|
||||||
{"version", no_argument, 0, 'V' },
|
{"help", no_argument, 0, 'h' },
|
||||||
{"help", no_argument, 0, 'h' },
|
{0, 0, 0, 0 }
|
||||||
{0, 0, 0, 0 }
|
};
|
||||||
};
|
|
||||||
|
|
||||||
c = getopt_long(argc, argv, "d:lr:D:vVh",
|
c = getopt_long(argc, argv, "d:lr:D:vVh",
|
||||||
long_options, &option_index);
|
long_options, &option_index);
|
||||||
if (c == -1)
|
if (c == -1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'D':
|
case 'd':
|
||||||
adeptDir = optarg;
|
activationDir = optarg;
|
||||||
break;
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
list = true;
|
list = true;
|
||||||
actions++;
|
actions++;
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
returnID = optarg;
|
returnID = optarg;
|
||||||
actions++;
|
actions++;
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'D':
|
||||||
deleteID = optarg;
|
deleteID = optarg;
|
||||||
actions++;
|
actions++;
|
||||||
break;
|
break;
|
||||||
case 'N':
|
case 'v':
|
||||||
notify = false;
|
verbose++;
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'V':
|
||||||
verbose++;
|
version();
|
||||||
break;
|
return 0;
|
||||||
case 'V':
|
case 'h':
|
||||||
version();
|
usage(argv[0]);
|
||||||
return 0;
|
return 0;
|
||||||
case 'h':
|
default:
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
return 0;
|
return -1;
|
||||||
default:
|
}
|
||||||
usage(argv[0]);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gourou::DRMProcessor::setLogLevel(verbose);
|
gourou::DRMProcessor::setLogLevel(verbose);
|
||||||
|
|
||||||
// By default, simply list books loaned
|
// By default, simply list books loaned
|
||||||
if (actions == 0)
|
if (actions == 0)
|
||||||
list = true;
|
list = true;
|
||||||
else if (actions != 1)
|
else if (actions != 1)
|
||||||
{
|
{
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
LoanMGT loanMGT;
|
LoanMGT loanMGT;
|
||||||
|
|
@ -454,50 +430,50 @@ int main(int argc, char** argv)
|
||||||
char *filename;
|
char *filename;
|
||||||
for (i=0; i<(int)ARRAY_SIZE(files); i++)
|
for (i=0; i<(int)ARRAY_SIZE(files); i++)
|
||||||
{
|
{
|
||||||
orig = *files[i];
|
orig = *files[i];
|
||||||
|
|
||||||
if (adeptDir)
|
if (activationDir)
|
||||||
{
|
{
|
||||||
std::string path = std::string(adeptDir) + std::string("/") + orig;
|
std::string path = std::string(activationDir) + std::string("/") + orig;
|
||||||
filename = strdup(path.c_str());
|
filename = strdup(path.c_str());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
filename = strdup(orig);
|
filename = strdup(orig);
|
||||||
*files[i] = findFile(filename);
|
*files[i] = findFile(filename);
|
||||||
free(filename);
|
free(filename);
|
||||||
if (!*files[i])
|
if (!*files[i])
|
||||||
{
|
{
|
||||||
std::cout << "Error : " << orig << " doesn't exists, did you activate your device ?" << std::endl;
|
std::cout << "Error : " << orig << " doesn't exists, did you activate your device ?" << std::endl;
|
||||||
hasErrors = true;
|
hasErrors = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasErrors)
|
if (hasErrors)
|
||||||
{
|
{
|
||||||
// In case of adept dir was provided by user
|
// In case of activation dir was provided by user
|
||||||
adeptDir = 0;
|
activationDir = 0;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adeptDir)
|
if (activationDir)
|
||||||
adeptDir = strdup(adeptDir); // For below free
|
activationDir = strdup(activationDir); // For below free
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
adeptDir = strdup(deviceFile);
|
activationDir = strdup(deviceFile);
|
||||||
adeptDir = dirname(adeptDir);
|
activationDir = dirname(activationDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = loanMGT.run();
|
ret = loanMGT.run();
|
||||||
|
|
||||||
end:
|
end:
|
||||||
for (i=0; i<(int)ARRAY_SIZE(files); i++)
|
for (i=0; i<(int)ARRAY_SIZE(files); i++)
|
||||||
{
|
{
|
||||||
if (*files[i])
|
if (*files[i])
|
||||||
free((void*)*files[i]);
|
free((void*)*files[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adeptDir)
|
if (activationDir)
|
||||||
free(adeptDir);
|
free(activationDir);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,16 +4,16 @@
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
* Redistributions of source code must retain the above copyright
|
||||||
notice, this list of conditions and the following disclaimer.
|
notice, this list of conditions and the following disclaimer.
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions and the following disclaimer in the
|
notice, this list of conditions and the following disclaimer in the
|
||||||
documentation and/or other materials provided with the distribution.
|
documentation and/or other materials provided with the distribution.
|
||||||
* Neither the name of the copyright holder nor the
|
* Neither the name of the copyright holder nor the
|
||||||
names of its contributors may be used to endorse or promote products
|
names of its contributors may be used to endorse or promote products
|
||||||
derived from this software without specific prior written permission.
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
|
@ -27,7 +27,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <libgen.h>
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
|
@ -51,13 +50,13 @@ static unsigned encryptionKeySize = 0;
|
||||||
static inline unsigned char htoi(unsigned char c)
|
static inline unsigned char htoi(unsigned char c)
|
||||||
{
|
{
|
||||||
if (c >= '0' && c <= '9')
|
if (c >= '0' && c <= '9')
|
||||||
c -= '0';
|
c -= '0';
|
||||||
else if (c >= 'a' && c <= 'f')
|
else if (c >= 'a' && c <= 'f')
|
||||||
c -= 'a' - 10;
|
c -= 'a' - 10;
|
||||||
else if (c >= 'A' && c <= 'F')
|
else if (c >= 'A' && c <= 'F')
|
||||||
c -= 'A' - 10;
|
c -= 'A' - 10;
|
||||||
else
|
else
|
||||||
EXCEPTION(gourou::USER_INVALID_INPUT, "Invalid character " << c << " in encryption key");
|
EXCEPTION(gourou::USER_INVALID_INPUT, "Invalid character " << c << " in encryption key");
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
@ -70,101 +69,94 @@ static inline bool endsWith(const std::string& s, const std::string& suffix)
|
||||||
class ADEPTRemove
|
class ADEPTRemove
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
int run()
|
int run()
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
gourou::DRMProcessor::ITEM_TYPE type;
|
gourou::DRMProcessor::ITEM_TYPE type;
|
||||||
DRMProcessorClientImpl client;
|
DRMProcessorClientImpl client;
|
||||||
gourou::DRMProcessor processor(&client, deviceFile, activationFile, devicekeyFile);
|
gourou::DRMProcessor processor(&client, deviceFile, activationFile, devicekeyFile);
|
||||||
|
|
||||||
std::string filename;
|
std::string filename;
|
||||||
if (outputFile)
|
if (!outputFile)
|
||||||
filename = outputFile;
|
filename = std::string(inputFile);
|
||||||
else
|
else
|
||||||
{
|
filename = outputFile;
|
||||||
filename = std::string(inputFile);
|
|
||||||
|
if (outputDir)
|
||||||
|
{
|
||||||
|
if (!fileExists(outputDir))
|
||||||
|
mkpath(outputDir);
|
||||||
|
|
||||||
if (outputDir)
|
filename = std::string(outputDir) + "/" + filename;
|
||||||
filename = std::string(outputDir) + "/" + filename;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (endsWith(filename, ".epub"))
|
|
||||||
type = gourou::DRMProcessor::ITEM_TYPE::EPUB;
|
|
||||||
else if (endsWith(filename, ".pdf"))
|
|
||||||
type = gourou::DRMProcessor::ITEM_TYPE::PDF;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
EXCEPTION(gourou::DRM_FORMAT_NOT_SUPPORTED, "Unsupported file format of " << filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
createPath(filename.c_str());
|
if (endsWith(filename, ".epub"))
|
||||||
|
type = gourou::DRMProcessor::ITEM_TYPE::EPUB;
|
||||||
|
else if (endsWith(filename, ".pdf"))
|
||||||
|
type = gourou::DRMProcessor::ITEM_TYPE::PDF;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EXCEPTION(gourou::DRM_FORMAT_NOT_SUPPORTED, "Unsupported file format of " << filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputFile != filename)
|
||||||
|
{
|
||||||
|
unlink(filename.c_str());
|
||||||
|
fileCopy(inputFile, filename.c_str());
|
||||||
|
processor.removeDRM(inputFile, filename, type, encryptionKey, encryptionKeySize);
|
||||||
|
std::cout << "DRM removed into new file " << filename << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Use temp file for PDF
|
||||||
|
if (type == gourou::DRMProcessor::ITEM_TYPE::PDF)
|
||||||
|
{
|
||||||
|
std::string tempFile = filename + ".tmp";
|
||||||
|
/* Be sure there is not already a temp file */
|
||||||
|
unlink(tempFile.c_str());
|
||||||
|
processor.removeDRM(filename, tempFile, type, encryptionKey, encryptionKeySize);
|
||||||
|
/* Original file must be removed before doing a copy... */
|
||||||
|
unlink(filename.c_str());
|
||||||
|
if (rename(tempFile.c_str(), filename.c_str()))
|
||||||
|
{
|
||||||
|
EXCEPTION(gourou::DRM_FILE_ERROR, "Unable to copy " << tempFile << " into " << filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
processor.removeDRM(inputFile, filename, type, encryptionKey, encryptionKeySize);
|
||||||
|
std::cout << "DRM removed from " << filename << std::endl;
|
||||||
|
}
|
||||||
|
} catch(std::exception& e)
|
||||||
|
{
|
||||||
|
std::cout << e.what() << std::endl;
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (inputFile != filename)
|
return ret;
|
||||||
{
|
|
||||||
unlink(filename.c_str());
|
|
||||||
fileCopy(inputFile, filename.c_str());
|
|
||||||
processor.removeDRM(inputFile, filename, type, encryptionKey, encryptionKeySize);
|
|
||||||
std::cout << "DRM removed into new file " << filename << std::endl;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Use temp file for PDF
|
|
||||||
if (type == gourou::DRMProcessor::ITEM_TYPE::PDF)
|
|
||||||
{
|
|
||||||
std::string tempFile = filename + ".tmp";
|
|
||||||
/* Be sure there is not already a temp file */
|
|
||||||
unlink(tempFile.c_str());
|
|
||||||
processor.removeDRM(filename, tempFile, type, encryptionKey, encryptionKeySize);
|
|
||||||
/* Original file must be removed before doing a copy... */
|
|
||||||
unlink(filename.c_str());
|
|
||||||
if (rename(tempFile.c_str(), filename.c_str()))
|
|
||||||
{
|
|
||||||
EXCEPTION(gourou::DRM_FILE_ERROR, "Unable to copy " << tempFile << " into " << filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
processor.removeDRM(inputFile, filename, type, encryptionKey, encryptionKeySize);
|
|
||||||
std::cout << "DRM removed from " << filename << std::endl;
|
|
||||||
}
|
|
||||||
} catch(std::exception& e)
|
|
||||||
{
|
|
||||||
std::cout << e.what() << std::endl;
|
|
||||||
ret = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void usage(const char* cmd)
|
static void usage(const char* cmd)
|
||||||
{
|
{
|
||||||
std::cout << basename((char*)cmd) << " remove ADEPT DRM (from Adobe) of EPUB/PDF file" << std::endl << std::endl;
|
std::cout << "Remove ADEPT DRM (from Adobe) of EPUB/PDF file" << std::endl;
|
||||||
|
|
||||||
std::cout << "Usage: " << basename((char*)cmd) << " [OPTIONS] file(.epub|pdf)" << std::endl << std::endl;
|
std::cout << "Usage: " << cmd << " [(-d|--device-file) device.xml] [(-a|--activation-file) activation.xml] [(-k|--device-key-file) devicesalt] [(-O|--output-dir) dir] [(-o|--output-file) output(.epub|.pdf|.der)] [(-v|--verbose)] [(-h|--help)] (-f|--input-file) file(.epub|pdf)" << std::endl << std::endl;
|
||||||
|
|
||||||
std::cout << "Global Options:" << std::endl;
|
std::cout << " " << "-d|--device-file" << "\t" << "device.xml file from eReader" << std::endl;
|
||||||
std::cout << " " << "-O|--output-dir" << "\t" << "Optional output directory were to put result (default ./) (not compatible with -o)" << std::endl;
|
std::cout << " " << "-a|--activation-file" << "\t" << "activation.xml file from eReader" << std::endl;
|
||||||
std::cout << " " << "-o|--output-file" << "\t" << "Optional output filename (default inplace DRM removal>) (not compatible with -O)" << std::endl;
|
std::cout << " " << "-k|--device-key-file" << "\t" << "private device key file (eg devicesalt/devkey.bin) from eReader" << std::endl;
|
||||||
std::cout << " " << "-f|--input-file" << "\t" << "Backward compatibility: EPUB/PDF file to process" << std::endl;
|
std::cout << " " << "-O|--output-dir" << "\t" << "Optional output directory were to put result (default ./)" << std::endl;
|
||||||
|
std::cout << " " << "-o|--output-file" << "\t" << "Optional output filename (default inplace DRM removal>)" << std::endl;
|
||||||
|
std::cout << " " << "-f|--input-file" << "\t" << "EPUB/PDF file to process" << std::endl;
|
||||||
std::cout << " " << "-v|--verbose" << "\t\t" << "Increase verbosity, can be set multiple times" << std::endl;
|
std::cout << " " << "-v|--verbose" << "\t\t" << "Increase verbosity, can be set multiple times" << std::endl;
|
||||||
std::cout << " " << "-V|--version" << "\t\t" << "Display libgourou version" << std::endl;
|
std::cout << " " << "-V|--version" << "\t\t" << "Display libgourou version" << std::endl;
|
||||||
std::cout << " " << "-h|--help" << "\t\t" << "This help" << std::endl;
|
std::cout << " " << "-h|--help" << "\t\t" << "This help" << std::endl;
|
||||||
|
|
||||||
std::cout << "ADEPT Options:" << std::endl;
|
|
||||||
std::cout << " " << "-D|--adept-directory" << "\t" << ".adept directory that must contains device.xml, activation.xml and devicesalt" << std::endl;
|
|
||||||
std::cout << " " << "-d|--device-file" << "\t" << "device.xml file from eReader" << std::endl;
|
|
||||||
std::cout << " " << "-a|--activation-file" << "\t" << "activation.xml file from eReader" << std::endl;
|
|
||||||
std::cout << " " << "-k|--device-key-file" << "\t" << "private device key file (eg devicesalt/devkey.bin) from eReader" << std::endl;
|
|
||||||
|
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
|
||||||
std::cout << "Environment:" << std::endl;
|
|
||||||
std::cout << "Device file, activation file and device key file are optionals. If not set, they are looked into :" << std::endl;
|
std::cout << "Device file, activation file and device key file are optionals. If not set, they are looked into :" << std::endl;
|
||||||
std::cout << " * $ADEPT_DIR environment variable" << std::endl;
|
|
||||||
std::cout << " * /home/<user>/.config/adept" << std::endl;
|
|
||||||
std::cout << " * Current directory" << std::endl;
|
std::cout << " * Current directory" << std::endl;
|
||||||
std::cout << " * .adept" << std::endl;
|
std::cout << " * .adept" << std::endl;
|
||||||
std::cout << " * adobe-digital-editions directory" << std::endl;
|
std::cout << " * adobe-digital-editions directory" << std::endl;
|
||||||
|
|
@ -177,93 +169,74 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
const char** files[] = {&devicekeyFile, &deviceFile, &activationFile};
|
const char** files[] = {&devicekeyFile, &deviceFile, &activationFile};
|
||||||
int verbose = gourou::DRMProcessor::getLogLevel();
|
int verbose = gourou::DRMProcessor::getLogLevel();
|
||||||
std::string _deviceFile, _activationFile, _devicekeyFile;
|
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
static struct option long_options[] = {
|
static struct option long_options[] = {
|
||||||
{"adept-directory", required_argument, 0, 'D' },
|
{"device-file", required_argument, 0, 'd' },
|
||||||
{"device-file", required_argument, 0, 'd' },
|
{"activation-file", required_argument, 0, 'a' },
|
||||||
{"activation-file", required_argument, 0, 'a' },
|
{"device-key-file", required_argument, 0, 'k' },
|
||||||
{"device-key-file", required_argument, 0, 'k' },
|
{"output-dir", required_argument, 0, 'O' },
|
||||||
{"output-dir", required_argument, 0, 'O' },
|
{"output-file", required_argument, 0, 'o' },
|
||||||
{"output-file", required_argument, 0, 'o' },
|
{"input-file", required_argument, 0, 'f' },
|
||||||
{"input-file", required_argument, 0, 'f' },
|
{"encryption-key", required_argument, 0, 'K' }, // Private option
|
||||||
{"encryption-key", required_argument, 0, 'K' }, // Private option
|
{"verbose", no_argument, 0, 'v' },
|
||||||
{"verbose", no_argument, 0, 'v' },
|
{"version", no_argument, 0, 'V' },
|
||||||
{"version", no_argument, 0, 'V' },
|
{"help", no_argument, 0, 'h' },
|
||||||
{"help", no_argument, 0, 'h' },
|
{0, 0, 0, 0 }
|
||||||
{0, 0, 0, 0 }
|
};
|
||||||
};
|
|
||||||
|
|
||||||
c = getopt_long(argc, argv, "D:d:a:k:O:o:f:K:vVh",
|
c = getopt_long(argc, argv, "d:a:k:O:o:f:K:vVh",
|
||||||
long_options, &option_index);
|
long_options, &option_index);
|
||||||
if (c == -1)
|
if (c == -1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'D':
|
case 'd':
|
||||||
_deviceFile = std::string(optarg) + "/device.xml";
|
deviceFile = optarg;
|
||||||
_activationFile = std::string(optarg) + "/activation.xml";
|
break;
|
||||||
_devicekeyFile = std::string(optarg) + "/devicesalt";
|
case 'a':
|
||||||
deviceFile = _deviceFile.c_str();
|
activationFile = optarg;
|
||||||
activationFile = _activationFile.c_str();
|
break;
|
||||||
devicekeyFile = _devicekeyFile.c_str();
|
case 'k':
|
||||||
break;
|
devicekeyFile = optarg;
|
||||||
case 'd':
|
break;
|
||||||
deviceFile = optarg;
|
case 'f':
|
||||||
break;
|
inputFile = optarg;
|
||||||
case 'a':
|
break;
|
||||||
activationFile = optarg;
|
case 'O':
|
||||||
break;
|
outputDir = optarg;
|
||||||
case 'k':
|
break;
|
||||||
devicekeyFile = optarg;
|
case 'o':
|
||||||
break;
|
outputFile = optarg;
|
||||||
case 'f':
|
break;
|
||||||
inputFile = optarg;
|
case 'K':
|
||||||
break;
|
encryptionKeyUser = optarg;
|
||||||
case 'O':
|
break;
|
||||||
outputDir = optarg;
|
case 'v':
|
||||||
break;
|
verbose++;
|
||||||
case 'o':
|
break;
|
||||||
outputFile = optarg;
|
case 'V':
|
||||||
break;
|
version();
|
||||||
case 'K':
|
return 0;
|
||||||
encryptionKeyUser = optarg;
|
case 'h':
|
||||||
break;
|
usage(argv[0]);
|
||||||
case 'v':
|
return 0;
|
||||||
verbose++;
|
default:
|
||||||
break;
|
usage(argv[0]);
|
||||||
case 'V':
|
return -1;
|
||||||
version();
|
}
|
||||||
return 0;
|
|
||||||
case 'h':
|
|
||||||
usage(argv[0]);
|
|
||||||
return 0;
|
|
||||||
default:
|
|
||||||
usage(argv[0]);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gourou::DRMProcessor::setLogLevel(verbose);
|
gourou::DRMProcessor::setLogLevel(verbose);
|
||||||
|
|
||||||
if (optind == argc-1)
|
|
||||||
inputFile = argv[optind];
|
|
||||||
|
|
||||||
if (!inputFile || (outputDir && !outputDir[0]) ||
|
if (!inputFile || (outputDir && !outputDir[0]) ||
|
||||||
(outputFile && !outputFile[0]))
|
(outputFile && !outputFile[0]))
|
||||||
{
|
{
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outputDir && outputFile)
|
|
||||||
{
|
|
||||||
std::cout << "Error : you cannot use both -o and -O" << std::endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ADEPTRemove remover;
|
ADEPTRemove remover;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
@ -271,56 +244,56 @@ int main(int argc, char** argv)
|
||||||
const char* orig;
|
const char* orig;
|
||||||
for (i=0; i<(int)ARRAY_SIZE(files); i++)
|
for (i=0; i<(int)ARRAY_SIZE(files); i++)
|
||||||
{
|
{
|
||||||
orig = *files[i];
|
orig = *files[i];
|
||||||
*files[i] = findFile(*files[i]);
|
*files[i] = findFile(*files[i]);
|
||||||
if (!*files[i])
|
if (!*files[i])
|
||||||
{
|
{
|
||||||
std::cout << "Error : " << orig << " doesn't exists, did you activate your device ?" << std::endl;
|
std::cout << "Error : " << orig << " doesn't exists, did you activate your device ?" << std::endl;
|
||||||
ret = -1;
|
ret = -1;
|
||||||
hasErrors = true;
|
hasErrors = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (encryptionKeyUser)
|
if (encryptionKeyUser)
|
||||||
{
|
{
|
||||||
int size = std::string(encryptionKeyUser).size();
|
int size = std::string(encryptionKeyUser).size();
|
||||||
if ((size % 2))
|
if ((size % 2))
|
||||||
{
|
{
|
||||||
std::cout << "Error : Encryption key must be odd length" << std::endl;
|
std::cout << "Error : Encryption key must be odd length" << std::endl;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (encryptionKeyUser[0] == '0' && encryptionKeyUser[1] == 'x')
|
if (encryptionKeyUser[0] == '0' && encryptionKeyUser[1] == 'x')
|
||||||
{
|
{
|
||||||
encryptionKeyUser += 2;
|
encryptionKeyUser += 2;
|
||||||
size -= 2;
|
size -= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
encryptionKey = new unsigned char[size/2];
|
encryptionKey = new unsigned char[size/2];
|
||||||
|
|
||||||
for(i=0; i<size; i+=2)
|
for(i=0; i<size; i+=2)
|
||||||
{
|
{
|
||||||
encryptionKey[i/2] = htoi(encryptionKeyUser[i]) << 4;
|
encryptionKey[i/2] = htoi(encryptionKeyUser[i]) << 4;
|
||||||
encryptionKey[i/2] |= htoi(encryptionKeyUser[i+1]);
|
encryptionKey[i/2] |= htoi(encryptionKeyUser[i+1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
encryptionKeySize = size/2;
|
encryptionKeySize = size/2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasErrors)
|
if (hasErrors)
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
ret = remover.run();
|
ret = remover.run();
|
||||||
|
|
||||||
end:
|
end:
|
||||||
for (i=0; i<(int)ARRAY_SIZE(files); i++)
|
for (i=0; i<(int)ARRAY_SIZE(files); i++)
|
||||||
{
|
{
|
||||||
if (*files[i])
|
if (*files[i])
|
||||||
free((void*)*files[i]);
|
free((void*)*files[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (encryptionKey)
|
if (encryptionKey)
|
||||||
free(encryptionKey);
|
free(encryptionKey);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -4,16 +4,16 @@
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
* Redistributions of source code must retain the above copyright
|
||||||
notice, this list of conditions and the following disclaimer.
|
notice, this list of conditions and the following disclaimer.
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions and the following disclaimer in the
|
notice, this list of conditions and the following disclaimer in the
|
||||||
documentation and/or other materials provided with the distribution.
|
documentation and/or other materials provided with the distribution.
|
||||||
* Neither the name of the copyright holder nor the
|
* Neither the name of the copyright holder nor the
|
||||||
names of its contributors may be used to endorse or promote products
|
names of its contributors may be used to endorse or promote products
|
||||||
derived from this software without specific prior written permission.
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
|
@ -42,12 +42,12 @@ class DRMProcessorClientImpl : public gourou::DRMProcessorClient
|
||||||
public:
|
public:
|
||||||
DRMProcessorClientImpl();
|
DRMProcessorClientImpl();
|
||||||
~DRMProcessorClientImpl();
|
~DRMProcessorClientImpl();
|
||||||
|
|
||||||
/* Digest interface */
|
/* Digest interface */
|
||||||
virtual void* createDigest(const std::string& digestName);
|
virtual void* createDigest(const std::string& digestName);
|
||||||
virtual void digestUpdate(void* handler, unsigned char* data, unsigned int length);
|
virtual int digestUpdate(void* handler, unsigned char* data, unsigned int length);
|
||||||
virtual void digestFinalize(void* handler,unsigned char* digestOut);
|
virtual int digestFinalize(void* handler,unsigned char* digestOut);
|
||||||
virtual void digest(const std::string& digestName, unsigned char* data, unsigned int length, unsigned char* digestOut);
|
virtual int digest(const std::string& digestName, unsigned char* data, unsigned int length, unsigned char* digestOut);
|
||||||
|
|
||||||
/* Random interface */
|
/* Random interface */
|
||||||
virtual void randBytes(unsigned char* bytesOut, unsigned int length);
|
virtual void randBytes(unsigned char* bytesOut, unsigned int length);
|
||||||
|
|
@ -56,90 +56,82 @@ public:
|
||||||
virtual std::string sendHTTPRequest(const std::string& URL, const std::string& POSTData=std::string(""), const std::string& contentType=std::string(""), std::map<std::string, std::string>* responseHeaders=0, int fd=0, bool resume=false);
|
virtual std::string sendHTTPRequest(const std::string& URL, const std::string& POSTData=std::string(""), const std::string& contentType=std::string(""), std::map<std::string, std::string>* responseHeaders=0, int fd=0, bool resume=false);
|
||||||
|
|
||||||
virtual void RSAPrivateEncrypt(const unsigned char* RSAKey, unsigned int RSAKeyLength,
|
virtual void RSAPrivateEncrypt(const unsigned char* RSAKey, unsigned int RSAKeyLength,
|
||||||
const RSA_KEY_TYPE keyType, const std::string& password,
|
const RSA_KEY_TYPE keyType, const std::string& password,
|
||||||
const unsigned char* data, unsigned dataLength,
|
const unsigned char* data, unsigned dataLength,
|
||||||
unsigned char* res);
|
unsigned char* res);
|
||||||
|
|
||||||
virtual void RSAPrivateDecrypt(const unsigned char* RSAKey, unsigned int RSAKeyLength,
|
virtual void RSAPrivateDecrypt(const unsigned char* RSAKey, unsigned int RSAKeyLength,
|
||||||
const RSA_KEY_TYPE keyType, const std::string& password,
|
const RSA_KEY_TYPE keyType, const std::string& password,
|
||||||
const unsigned char* data, unsigned dataLength,
|
const unsigned char* data, unsigned dataLength,
|
||||||
unsigned char* res);
|
unsigned char* res);
|
||||||
|
|
||||||
virtual void RSAPublicEncrypt(const unsigned char* RSAKey, unsigned int RSAKeyLength,
|
virtual void RSAPublicEncrypt(const unsigned char* RSAKey, unsigned int RSAKeyLength,
|
||||||
const RSA_KEY_TYPE keyType,
|
const RSA_KEY_TYPE keyType,
|
||||||
const unsigned char* data, unsigned dataLength,
|
const unsigned char* data, unsigned dataLength,
|
||||||
unsigned char* res);
|
unsigned char* res);
|
||||||
|
|
||||||
virtual void* generateRSAKey(int keyLengthBits);
|
virtual void* generateRSAKey(int keyLengthBits);
|
||||||
virtual void destroyRSAHandler(void* handler);
|
virtual void destroyRSAHandler(void* handler);
|
||||||
|
|
||||||
virtual void extractRSAPublicKey(void* RSAKeyHandler, unsigned char** keyOut, unsigned int* keyOutLength);
|
virtual void extractRSAPublicKey(void* RSAKeyHandler, unsigned char** keyOut, unsigned int* keyOutLength);
|
||||||
virtual void extractRSAPrivateKey(void* RSAKeyHandler, unsigned char** keyOut, unsigned int* keyOutLength);
|
virtual void extractRSAPrivateKey(void* RSAKeyHandler, unsigned char** keyOut, unsigned int* keyOutLength);
|
||||||
virtual void extractCertificate(const unsigned char* RSAKey, unsigned int RSAKeyLength,
|
virtual void extractCertificate(const unsigned char* RSAKey, unsigned int RSAKeyLength,
|
||||||
const RSA_KEY_TYPE keyType, const std::string& password,
|
const RSA_KEY_TYPE keyType, const std::string& password,
|
||||||
unsigned char** certOut, unsigned int* certOutLength);
|
unsigned char** certOut, unsigned int* certOutLength);
|
||||||
|
|
||||||
/* Crypto interface */
|
/* Crypto interface */
|
||||||
virtual void encrypt(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
virtual void Encrypt(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
||||||
const unsigned char* key, unsigned int keyLength,
|
const unsigned char* key, unsigned int keyLength,
|
||||||
const unsigned char* iv, unsigned int ivLength,
|
const unsigned char* iv, unsigned int ivLength,
|
||||||
const unsigned char* dataIn, unsigned int dataInLength,
|
const unsigned char* dataIn, unsigned int dataInLength,
|
||||||
unsigned char* dataOut, unsigned int* dataOutLength);
|
unsigned char* dataOut, unsigned int* dataOutLength);
|
||||||
|
|
||||||
virtual void* encryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
virtual void* EncryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
||||||
const unsigned char* key, unsigned int keyLength,
|
const unsigned char* key, unsigned int keyLength,
|
||||||
const unsigned char* iv=0, unsigned int ivLength=0);
|
const unsigned char* iv=0, unsigned int ivLength=0);
|
||||||
|
|
||||||
|
|
||||||
virtual void encryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
|
virtual void EncryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
|
||||||
unsigned char* dataOut, unsigned int* dataOutLength);
|
unsigned char* dataOut, unsigned int* dataOutLength);
|
||||||
virtual void encryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength);
|
virtual void EncryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength);
|
||||||
|
|
||||||
virtual void decrypt(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
virtual void Decrypt(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
||||||
const unsigned char* key, unsigned int keyLength,
|
const unsigned char* key, unsigned int keyLength,
|
||||||
const unsigned char* iv, unsigned int ivLength,
|
const unsigned char* iv, unsigned int ivLength,
|
||||||
const unsigned char* dataIn, unsigned int dataInLength,
|
const unsigned char* dataIn, unsigned int dataInLength,
|
||||||
unsigned char* dataOut, unsigned int* dataOutLength);
|
unsigned char* dataOut, unsigned int* dataOutLength);
|
||||||
|
|
||||||
virtual void* decryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
virtual void* DecryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
||||||
const unsigned char* key, unsigned int keyLength,
|
const unsigned char* key, unsigned int keyLength,
|
||||||
const unsigned char* iv=0, unsigned int ivLength=0);
|
const unsigned char* iv=0, unsigned int ivLength=0);
|
||||||
|
|
||||||
virtual void decryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
|
virtual void DecryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
|
||||||
unsigned char* dataOut, unsigned int* dataOutLength);
|
unsigned char* dataOut, unsigned int* dataOutLength);
|
||||||
virtual void decryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength);
|
virtual void DecryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength);
|
||||||
|
|
||||||
/* ZIP Interface */
|
/* ZIP Interface */
|
||||||
virtual void* zipOpen(const std::string& path);
|
virtual void* zipOpen(const std::string& path);
|
||||||
|
|
||||||
virtual void zipReadFile(void* handler, const std::string& path, gourou::ByteArray& result, bool decompress=true);
|
|
||||||
|
|
||||||
virtual void zipWriteFile(void* handler, const std::string& path, gourou::ByteArray& content);
|
|
||||||
|
|
||||||
virtual void zipDeleteFile(void* handler, const std::string& path);
|
|
||||||
|
|
||||||
virtual void zipClose(void* handler);
|
|
||||||
|
|
||||||
virtual void inflate(gourou::ByteArray& data, gourou::ByteArray& result,
|
|
||||||
int wbits=-15);
|
|
||||||
|
|
||||||
|
virtual void zipReadFile(void* handler, const std::string& path, gourou::ByteArray& result, bool decompress=true);
|
||||||
|
|
||||||
|
virtual void zipWriteFile(void* handler, const std::string& path, gourou::ByteArray& content);
|
||||||
|
|
||||||
|
virtual void zipDeleteFile(void* handler, const std::string& path);
|
||||||
|
|
||||||
|
virtual void zipClose(void* handler);
|
||||||
|
|
||||||
|
virtual void inflate(gourou::ByteArray& data, gourou::ByteArray& result,
|
||||||
|
int wbits=-15);
|
||||||
|
|
||||||
virtual void deflate(gourou::ByteArray& data, gourou::ByteArray& result,
|
virtual void deflate(gourou::ByteArray& data, gourou::ByteArray& result,
|
||||||
int wbits=-15, int compressionLevel=8);
|
int wbits=-15, int compressionLevel=8);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void padWithPKCS1(unsigned char* out, unsigned int outLength,
|
|
||||||
const unsigned char* in, unsigned int inLength);
|
|
||||||
void padWithPKCS1Type2(unsigned char* out, unsigned int outLength,
|
|
||||||
const unsigned char* in, unsigned int inLength);
|
|
||||||
|
|
||||||
#if OPENSSL_VERSION_MAJOR >= 3
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
OSSL_PROVIDER *legacy, *deflt;
|
OSSL_PROVIDER *legacy, *deflt;
|
||||||
#else
|
#else
|
||||||
void *legacy, *deflt;
|
void *legacy, *deflt;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char cookiejar[64];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
#include <iostream>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <libgen.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "utils_common.h"
|
|
||||||
|
|
||||||
#ifndef DEFAULT_UTIL
|
|
||||||
#define DEFAULT_UTIL "acsmdownloader"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Inspired from https://discourse.appimage.org/t/call-alternative-binary-from-appimage/93/10*/
|
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
|
||||||
{
|
|
||||||
char* util, *argv0;
|
|
||||||
char* mountPoint = getenv("APPDIR");
|
|
||||||
std::string fullPath;
|
|
||||||
|
|
||||||
/* Original command is in ARGV0 env variable*/
|
|
||||||
argv0 = strdup(getenv("ARGV0"));
|
|
||||||
util = basename(argv0);
|
|
||||||
|
|
||||||
fullPath = std::string(mountPoint) + util;
|
|
||||||
|
|
||||||
if (std::string(util) == "launcher" || !pathExists(fullPath.c_str()))
|
|
||||||
fullPath = std::string(mountPoint) + DEFAULT_UTIL;
|
|
||||||
|
|
||||||
free(argv0);
|
|
||||||
|
|
||||||
argv[0] = strdup(fullPath.c_str());
|
|
||||||
|
|
||||||
if (execvp(argv[0], argv))
|
|
||||||
std::cout << "Unable to launch '" << argv[0] << "'" << std::endl;
|
|
||||||
|
|
||||||
/* Should not happens */
|
|
||||||
free(argv[0]);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@ -1,61 +0,0 @@
|
||||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
|
|
||||||
.TH ACSMDOWNLOADER "1" "January 2023" "acsmdownloader download EPUB file from ACSM request file" "User Commands"
|
|
||||||
.SH NAME
|
|
||||||
acsmdownloader \- download EPUB file from ACSM request file
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.B acsmdownloader
|
|
||||||
[\fI\,OPTIONS\/\fR] \fI\,file.acsm\/\fR
|
|
||||||
.SH DESCRIPTION
|
|
||||||
Download EPUB file from ACSM request file
|
|
||||||
.SS "Global Options:"
|
|
||||||
.TP
|
|
||||||
\fB\-O\fR|\-\-output\-dir
|
|
||||||
Optional output directory were to put result (default ./)
|
|
||||||
.TP
|
|
||||||
\fB\-o\fR|\-\-output\-file
|
|
||||||
Optional output filename (default <title.(epub|pdf|der)>)
|
|
||||||
.TP
|
|
||||||
\fB\-f\fR|\-\-acsm\-file
|
|
||||||
Backward compatibility: ACSM request file for epub download
|
|
||||||
.TP
|
|
||||||
\fB\-e\fR|\-\-export\-private\-key
|
|
||||||
Export private key in DER format
|
|
||||||
.TP
|
|
||||||
\fB\-r\fR|\-\-resume
|
|
||||||
Try to resume download (in case of previous failure)
|
|
||||||
.TP
|
|
||||||
\fB\-v\fR|\-\-verbose
|
|
||||||
Increase verbosity, can be set multiple times
|
|
||||||
.TP
|
|
||||||
\fB\-V\fR|\-\-version
|
|
||||||
Display libgourou version
|
|
||||||
.TP
|
|
||||||
\fB\-h\fR|\-\-help
|
|
||||||
This help
|
|
||||||
.SS "ADEPT Options:"
|
|
||||||
.TP
|
|
||||||
\fB\-D\fR|\-\-adept\-directory
|
|
||||||
\&.adept directory that must contains device.xml, activation.xml and devicesalt
|
|
||||||
.TP
|
|
||||||
\fB\-d\fR|\-\-device\-file
|
|
||||||
device.xml file from eReader
|
|
||||||
.TP
|
|
||||||
\fB\-a\fR|\-\-activation\-file
|
|
||||||
activation.xml file from eReader
|
|
||||||
.TP
|
|
||||||
\fB\-k\fR|\-\-device\-key\-file
|
|
||||||
private device key file (eg devicesalt/devkey.bin) from eReader
|
|
||||||
.SH ENVIRONMENT
|
|
||||||
Device file, activation file and device key file are optionals. If not set, they are looked into :
|
|
||||||
.IP
|
|
||||||
* $ADEPT_DIR environment variable
|
|
||||||
.IP
|
|
||||||
* /home/<user>/.config/adept
|
|
||||||
.IP
|
|
||||||
* Current directory
|
|
||||||
.IP
|
|
||||||
* .adept
|
|
||||||
.IP
|
|
||||||
* adobe\-digital\-editions directory
|
|
||||||
.IP
|
|
||||||
* .adobe\-digital\-editions directory
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
||||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
|
|
||||||
.TH ADEPT_ACTIVATE "1" "January 2023" "adept_activate create new device files used by ADEPT DRM" "User Commands"
|
|
||||||
.SH NAME
|
|
||||||
adept_activate create new device files used by ADEPT DRM
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.B adept_activate
|
|
||||||
\fI\,OPTIONS\/\fR
|
|
||||||
.SH DESCRIPTION
|
|
||||||
Create new device files used by ADEPT DRM
|
|
||||||
.SS "Global Options:"
|
|
||||||
.TP
|
|
||||||
\fB\-a\fR|\-\-anonymous
|
|
||||||
Anonymous account, no need for username/password (Use it only with a DRM removal software)
|
|
||||||
.TP
|
|
||||||
\fB\-u\fR|\-\-username
|
|
||||||
AdobeID username (ie adobe.com email account)
|
|
||||||
.TP
|
|
||||||
\fB\-p\fR|\-\-password
|
|
||||||
AdobeID password (asked if not set via command line)
|
|
||||||
.TP
|
|
||||||
\fB\-O\fR|\-\-output\-dir
|
|
||||||
Optional output directory were to put result (default ./.adept). This directory must not already exists
|
|
||||||
.TP
|
|
||||||
\fB\-H\fR|\-\-hobbes\-version
|
|
||||||
Force RMSDK version to a specific value (default: version of current librmsdk)
|
|
||||||
.TP
|
|
||||||
\fB\-r\fR|\-\-random\-serial
|
|
||||||
Generate a random device serial (if not set, it will be dependent of your current configuration)
|
|
||||||
.TP
|
|
||||||
\fB\-v\fR|\-\-verbose
|
|
||||||
Increase verbosity, can be set multiple times
|
|
||||||
.TP
|
|
||||||
\fB\-V\fR|\-\-version
|
|
||||||
Display libgourou version
|
|
||||||
.TP
|
|
||||||
\fB\-h\fR|\-\-help
|
|
||||||
This help
|
|
||||||
.PP
|
|
||||||
Usage: adept_activate OPTIONS
|
|
||||||
.SS "Global Options:"
|
|
||||||
.TP
|
|
||||||
\fB\-a\fR|\-\-anonymous
|
|
||||||
Anonymous account, no need for username/password (Use it only with a DRM removal software)
|
|
||||||
.TP
|
|
||||||
\fB\-u\fR|\-\-username
|
|
||||||
AdobeID username (ie adobe.com email account)
|
|
||||||
.TP
|
|
||||||
\fB\-p\fR|\-\-password
|
|
||||||
AdobeID password (asked if not set via command line)
|
|
||||||
.TP
|
|
||||||
\fB\-O\fR|\-\-output\-dir
|
|
||||||
Optional output directory were to put result (default ./.adept). This directory must not already exists
|
|
||||||
.TP
|
|
||||||
\fB\-H\fR|\-\-hobbes\-version
|
|
||||||
Force RMSDK version to a specific value (default: version of current librmsdk)
|
|
||||||
.TP
|
|
||||||
\fB\-r\fR|\-\-random\-serial
|
|
||||||
Generate a random device serial (if not set, it will be dependent of your current configuration)
|
|
||||||
.TP
|
|
||||||
\fB\-v\fR|\-\-verbose
|
|
||||||
Increase verbosity, can be set multiple times
|
|
||||||
.TP
|
|
||||||
\fB\-V\fR|\-\-version
|
|
||||||
Display libgourou version
|
|
||||||
.TP
|
|
||||||
\fB\-h\fR|\-\-help
|
|
||||||
This help
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
|
|
||||||
.TH ADEPT_LOAN_MGT "1" "January 2023" "adept_loan_mgt manage loaned books" "User Commands"
|
|
||||||
.SH NAME
|
|
||||||
adept_loan_mgt manage loaned books
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.B adept_loan_mgt
|
|
||||||
[\fI\,OPTIONS\/\fR]
|
|
||||||
.SH DESCRIPTION
|
|
||||||
Manage ADEPT loaned books
|
|
||||||
.SS "Global Options:"
|
|
||||||
.TP
|
|
||||||
\fB\-l\fR|\-\-list
|
|
||||||
List all loaned books
|
|
||||||
.TP
|
|
||||||
\fB\-r\fR|\-\-return
|
|
||||||
Return a loaned book
|
|
||||||
.TP
|
|
||||||
\fB\-d\fR|\-\-delete
|
|
||||||
Delete a loan entry without returning it
|
|
||||||
.TP
|
|
||||||
\fB\-v\fR|\-\-verbose
|
|
||||||
Increase verbosity, can be set multiple times
|
|
||||||
.TP
|
|
||||||
\fB\-V\fR|\-\-version
|
|
||||||
Display libgourou version
|
|
||||||
.TP
|
|
||||||
\fB\-h\fR|\-\-help
|
|
||||||
This help
|
|
||||||
.SS "ADEPT Options:"
|
|
||||||
.TP
|
|
||||||
\fB\-D\fR|\-\-adept\-directory
|
|
||||||
\&.adept directory that must contains device.xml, activation.xml and devicesalt
|
|
||||||
.SH ENVIRONMENT
|
|
||||||
.SS "ADEPT directory is optional. If not set, it's looked into :"
|
|
||||||
.IP
|
|
||||||
* $ADEPT_DIR environment variable
|
|
||||||
.IP
|
|
||||||
* /home/<user>/.config/adept
|
|
||||||
.IP
|
|
||||||
* Current directory
|
|
||||||
.IP
|
|
||||||
* .adept
|
|
||||||
.IP
|
|
||||||
* adobe\-digital\-editions directory
|
|
||||||
.IP
|
|
||||||
* .adobe\-digital\-editions directory
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
|
|
||||||
.TH ADEPT_REMOVE "1" "January 2023" "adept_remove remove ADEPT DRM (from Adobe) of EPUB/PDF file" "User Commands"
|
|
||||||
.SH NAME
|
|
||||||
adept_remove remove ADEPT DRM (from Adobe) of EPUB/PDF file
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.B adept_remove
|
|
||||||
[\fI\,OPTIONS\/\fR] \fI\,file(.epub|pdf)\/\fR
|
|
||||||
.SH DESCRIPTION
|
|
||||||
Remove ADEPT DRM (from Adobe) of EPUB/PDF file
|
|
||||||
.SS "Global Options:"
|
|
||||||
.TP
|
|
||||||
\fB\-O\fR|\-\-output\-dir
|
|
||||||
Optional output directory were to put result (default ./)
|
|
||||||
.TP
|
|
||||||
\fB\-o\fR|\-\-output\-file
|
|
||||||
Optional output filename (default inplace DRM removal>)
|
|
||||||
.TP
|
|
||||||
\fB\-f\fR|\-\-input\-file
|
|
||||||
Backward compatibility: EPUB/PDF file to process
|
|
||||||
.TP
|
|
||||||
\fB\-v\fR|\-\-verbose
|
|
||||||
Increase verbosity, can be set multiple times
|
|
||||||
.TP
|
|
||||||
\fB\-V\fR|\-\-version
|
|
||||||
Display libgourou version
|
|
||||||
.TP
|
|
||||||
\fB\-h\fR|\-\-help
|
|
||||||
This help
|
|
||||||
.SS "ADEPT Options:"
|
|
||||||
.TP
|
|
||||||
\fB\-D\fR|\-\-adept\-directory
|
|
||||||
\&.adept directory that must contains device.xml, activation.xml and devicesalt
|
|
||||||
.TP
|
|
||||||
\fB\-d\fR|\-\-device\-file
|
|
||||||
device.xml file from eReader
|
|
||||||
.TP
|
|
||||||
\fB\-a\fR|\-\-activation\-file
|
|
||||||
activation.xml file from eReader
|
|
||||||
.TP
|
|
||||||
\fB\-k\fR|\-\-device\-key\-file
|
|
||||||
private device key file (eg devicesalt/devkey.bin) from eReader
|
|
||||||
.SH ENVIRONMENT
|
|
||||||
.SS "Device file, activation file and device key file are optionals. If not set, they are looked into :"
|
|
||||||
.IP
|
|
||||||
* $ADEPT_DIR environment variable
|
|
||||||
.IP
|
|
||||||
* /home/<user>/.config/adept
|
|
||||||
.IP
|
|
||||||
* Current directory
|
|
||||||
.IP
|
|
||||||
* .adept
|
|
||||||
.IP
|
|
||||||
* adobe\-digital\-editions directory
|
|
||||||
.IP
|
|
||||||
* .adobe\-digital\-editions directory
|
|
||||||
|
|
@ -4,16 +4,16 @@
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
* Redistributions of source code must retain the above copyright
|
||||||
notice, this list of conditions and the following disclaimer.
|
notice, this list of conditions and the following disclaimer.
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions and the following disclaimer in the
|
notice, this list of conditions and the following disclaimer in the
|
||||||
documentation and/or other materials provided with the distribution.
|
documentation and/or other materials provided with the distribution.
|
||||||
* Neither the name of the copyright holder nor the
|
* Neither the name of the copyright holder nor the
|
||||||
names of its contributors may be used to endorse or promote products
|
names of its contributors may be used to endorse or promote products
|
||||||
derived from this software without specific prior written permission.
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
|
@ -33,7 +33,6 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <libgen.h>
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
|
@ -52,42 +51,28 @@ void version(void)
|
||||||
std::cout << "Current libgourou version : " << gourou::DRMProcessor::VERSION << std::endl ;
|
std::cout << "Current libgourou version : " << gourou::DRMProcessor::VERSION << std::endl ;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pathExists(const char* path)
|
bool fileExists(const char* filename)
|
||||||
{
|
{
|
||||||
struct stat _stat;
|
struct stat _stat;
|
||||||
int ret = stat(path, &_stat);
|
int ret = stat(filename, &_stat);
|
||||||
|
|
||||||
return (ret == 0);
|
return (ret == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* findFile(const char* filename, bool inDefaultDirs)
|
const char* findFile(const char* filename, bool inDefaultDirs)
|
||||||
{
|
{
|
||||||
std::string path;
|
if (fileExists(filename))
|
||||||
|
return strdup(filename);
|
||||||
const char* adeptDir = getenv("ADEPT_DIR");
|
|
||||||
if (adeptDir && adeptDir[0])
|
|
||||||
{
|
|
||||||
path = adeptDir + std::string("/") + filename;
|
|
||||||
if (pathExists(path.c_str()))
|
|
||||||
return strdup(path.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
path = gourou::DRMProcessor::getDefaultAdeptDir() + filename;
|
|
||||||
if (pathExists(path.c_str()))
|
|
||||||
return strdup(path.c_str());
|
|
||||||
|
|
||||||
if (pathExists(filename))
|
|
||||||
return strdup(filename);
|
|
||||||
|
|
||||||
if (!inDefaultDirs) return 0;
|
if (!inDefaultDirs) return 0;
|
||||||
|
|
||||||
for (int i=0; i<(int)ARRAY_SIZE(defaultDirs); i++)
|
for (int i=0; i<(int)ARRAY_SIZE(defaultDirs); i++)
|
||||||
{
|
{
|
||||||
path = std::string(defaultDirs[i]) + filename;
|
std::string path = std::string(defaultDirs[i]) + filename;
|
||||||
if (pathExists(path.c_str()))
|
if (fileExists(path.c_str()))
|
||||||
return strdup(path.c_str());
|
return strdup(path.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -113,52 +98,30 @@ void mkpath(const char *dir)
|
||||||
|
|
||||||
void fileCopy(const char* in, const char* out)
|
void fileCopy(const char* in, const char* out)
|
||||||
{
|
{
|
||||||
char buffer[4096], *_buffer;
|
char buffer[4096];
|
||||||
int ret, ret2, fdIn, fdOut;
|
int ret, fdIn, fdOut;
|
||||||
|
|
||||||
fdIn = open(in, O_RDONLY);
|
fdIn = open(in, O_RDONLY);
|
||||||
|
|
||||||
if (!fdIn)
|
if (!fdIn)
|
||||||
EXCEPTION(gourou::CLIENT_FILE_ERROR, "Unable to open " << in);
|
EXCEPTION(gourou::CLIENT_FILE_ERROR, "Unable to open " << in);
|
||||||
|
|
||||||
fdOut = gourou::createNewFile(out);
|
fdOut = gourou::createNewFile(out);
|
||||||
|
|
||||||
if (!fdOut)
|
if (!fdOut)
|
||||||
{
|
{
|
||||||
close (fdIn);
|
close (fdIn);
|
||||||
EXCEPTION(gourou::CLIENT_FILE_ERROR, "Unable to open " << out);
|
EXCEPTION(gourou::CLIENT_FILE_ERROR, "Unable to open " << out);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
ret = ::read(fdIn, buffer, sizeof(buffer));
|
ret = ::read(fdIn, buffer, sizeof(buffer));
|
||||||
if (ret <= 0)
|
if (ret <= 0)
|
||||||
break;
|
break;
|
||||||
do
|
::write(fdOut, buffer, ret);
|
||||||
{
|
|
||||||
_buffer = buffer;
|
|
||||||
ret2 = ::write(fdOut, _buffer, ret);
|
|
||||||
if (ret2 >= 0)
|
|
||||||
{
|
|
||||||
ret -= ret2;
|
|
||||||
_buffer += ret2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
EXCEPTION(gourou::CLIENT_FILE_ERROR, "Error writing " << out);
|
|
||||||
}
|
|
||||||
} while (ret);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
close (fdIn);
|
close (fdIn);
|
||||||
close (fdOut);
|
close (fdOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
void createPath(const char* filename)
|
|
||||||
{
|
|
||||||
char* basepath = strdup(filename);
|
|
||||||
char* outputDir = dirname(basepath);
|
|
||||||
if (outputDir && !pathExists(outputDir))
|
|
||||||
mkpath(outputDir);
|
|
||||||
free(basepath);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -4,16 +4,16 @@
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
* Redistributions of source code must retain the above copyright
|
||||||
notice, this list of conditions and the following disclaimer.
|
notice, this list of conditions and the following disclaimer.
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions and the following disclaimer in the
|
notice, this list of conditions and the following disclaimer in the
|
||||||
documentation and/or other materials provided with the distribution.
|
documentation and/or other materials provided with the distribution.
|
||||||
* Neither the name of the copyright holder nor the
|
* Neither the name of the copyright holder nor the
|
||||||
names of its contributors may be used to endorse or promote products
|
names of its contributors may be used to endorse or promote products
|
||||||
derived from this software without specific prior written permission.
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
|
@ -50,9 +50,9 @@ void version(void);
|
||||||
const char* findFile(const char* filename, bool inDefaultDirs=true);
|
const char* findFile(const char* filename, bool inDefaultDirs=true);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Does the file (or directory) exists
|
* @brief Does the file (or directory exists)
|
||||||
*/
|
*/
|
||||||
bool pathExists(const char* path);
|
bool fileExists(const char* filename);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Recursively created dir
|
* @brief Recursively created dir
|
||||||
|
|
@ -64,9 +64,4 @@ void mkpath(const char *dir);
|
||||||
*/
|
*/
|
||||||
void fileCopy(const char* in, const char* out);
|
void fileCopy(const char* in, const char* out);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Create intermediate directories if it does not exists
|
|
||||||
*/
|
|
||||||
void createPath(const char* filename);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue