Sony DADC User Rights Management Solution

Common Gateway Platform Software Development Kit (SDK)

Purpose

This document aims to provide an overview on Common Gateway Platform SDK (CGP SDK). CGP SDK fulfills functions that work on Android and iOS.

Features

CGP SDK has the following functions:

  • Common Bookshelf, to allow users to share e-books between different store applications
  • Marlin DRM Content Protection
  • Bookmark Synchronization
  • Rental and Gift, allowing users to lend or give books to friends
  • Management of records, such as adding, deleting, and selling of eBooks. Stores that use URMS need to set up the payment system for this function.

Target Platform

CGP SDK supports the following platforms.

Android 4.1 or later
iOS 8.0 or later

Usage

Use Debug SDK to debug for stores in development. It offers some anti-tampering features, such as anti-debugger checks. Using Release SDK will always crash when running from an IDE(xCode). Don’t use it for live online stores.

If you use Release SDK on iOS you need to update the final binary file and resign. This is because Release SDK offers an one anti-tampering feature that checks the file integrity to avoid modification and resigning by attackers. The easiest way to do this is to use additional xCode script in “Build Phases” configuration. The script triggers external binary “scp-update-binary” with the argument “urms.nwdb” to update checksums in the final binary binary. After that, xCode automatically signs the output binary.

if [ "$PLATFORM_NAME" == "iphoneos" ]; then
${PROJECT_DIR}/../libs/scp-update-binary --binary=${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/${PRODUCT_NAME} ${PROJECT_DIR}/../libs/urms.nwdb
fi

Required files, Android

liburms.so

URMS SDK shared library for Android

  • Provides the core functions of CGP SDK as well as an API for decryption
  • Should be placed under libs/armeabi directory

urms-sdk-android.jar

CGP SDK Java library for Android.

  • Sets up classes to use liburms.so from Java.
  • Should be added to Android project class path.

Required files, iOS (iOSSmtc)

CGP.framework

CGP SDK iOS framework.

  • Provides the core functions of CGP SDK
  • Should be added to iOS project

Synchronous/Asynchronous API usage

Most URMS-API tasks can send requests to the server so we recommend using asynchronous calls for all tasks that require network communication, unless your application contains an asynchronous mechanism.

For iOS, do not run network operations synchronously on the main thread.

Global SDK Management

Global tasks can be triggered only if URMS is initialized Reset them only in an emergency:

  • initialize
  • isinitialized
  • shutdown
  • reset

Multi Store List

This feature allows for updating the list of supported retailers on the reader application without needing to issue a new release of the software. It works by providing a list of stores through the GetStoresTask. This list is maintained on the CGP server.

This feature is optional. If your reader is directly connected to a single store or a fixed list of stores it is not required to fetch this list.

When the Reader application starts, or at the user login screen, the software requests the list of stores available. The application must provide an application identifier (pin/key). The response contains the list of stores registered for the application. The list includes the endpoint of the store as well as a list of supported features.

Workflow diagram for Multi Store List

Feature List

The feature list describes the set of features supported by the store. The documentation of the features describe the interface between the reader and the store. The idea is that a reader can implement any number of features, though some are optional and can be disabled by the reader without affecting the application. For example, the authentication scheme is a required feature, and the option to buy books via the app is optional.

If a retailer wants to be added to the list for a reader application, the retailer must support all of the mandatory features for that reader. Note that there is no check on the CGP server if all requirements are met.

Store Features

For the Android Sample Application, Token Authentication is mandatory, while buy and lend are optional.

For the iOS Sample Application, Token Authentication is mandatory.  There are no optional features.

Token Authentication

This feature is used to authenticate a user at the store and request an authToken. The authToken is required for registering the user’s device at the CGP server.

The returned token needs to be added as the header field “Authorization.” The word “Token” should be added to every subsequent request to the store.

The header field might look like this:

Authorization: Token c9a15696-0fe2-43e5-804d-67ebbc48a73f

The returned authToken is needed as an input parameter for the CreateProfileTask.

Request:

POST<storeUrl>auth/login

POST parameters encoded as JSON:

username user’s name, for access to store
password user password

Response encoded as JSON:

authToken token required for the CreateProfileTask
token token for all further requests to the store

Errors:

HTTP 401 – Unauthorized: Unknown user or incorrect username/password

Sample request:

POST /sample-store/client/auth/login HTTP/1.1
Content-Length: 31
Content-Type: application/json; charset=UTF-8
Host: 172.26.8.72:8080
Connection: Keep-Alive

{"password":"c","username":"c"}

Sample response:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: application/json;charset=UTF-8
Content-Length: 87
Date: Fri, 14 Oct 2016 09:17:03 GMT

{"authToken":"2398:eu:gz5vs2gjvbfstk7d","token":"649ee596-b779-4cf8-9398-10c24bea8af8"}

Sample Error:

HTTP/1.1 401 Unauthorized
Server: Apache-Coyote/1.1
Content-Length: 0
Date: Fri, 14 Oct 2016 09:22:54 GMT

Buy

This feature allows purchasing books with the client application

Request:
POST stores/books/{bookId}/buy

URL parameters:

bookID Code used by the store to identify the eBook

POST parameters encoded as json:

None

Response:

None

Errors:

HTTP 500 – Internal Server Error The CGP server returns an error. The detailed error will be contained in the body of the response.
HTTP 502 – Bad Gateway The system cannot reach the CGP server

Sample request:

POST /sample-store/client/stores/books/102/buy HTTP/1.1
Authorization: Token 444c6825-bb97-4c97-952b-b09931f12a94
Content-Length: 0
Host: 172.26.8.72:8080
Connection: Keep-Alive

Sample response:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Length: 0
Date: Fri, 14 Oct 2016 10:18:49 GMT

Sample error:

500 Internal Server Error
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=utf-8
Content-Language: en
Content-Length: 1131
Date: Fri, 14 Oct 2016 10:24:51 GMT
Connection: close

...

HTTP Status 500 - CGP error [1000] [Already book exists: User already owns this book]

...

Lend

This feature allows lending books from the store with the client application.

Request:
POST stores/books/{bookId}/lend

URL parameters:

bookID the store’s identifier of the book

POST parameters encoded as JSON:

None

Response:

None

Errors:

HTTP 500 – Internal Server Error CGP server returns an error. The detailed error will be contained in the body of the response.
HTTP 502 – Bad Gateway The CGP server can not be reached.

Sample request:

POST /sample-store/client/stores/books/103/lend HTTP/1.1
Authorization: Token 444c6825-bb97-4c97-952b-b09931f12a94
Content-Length: 0
Host: 172.26.8.72:8080
Connection: Keep-Alive

Example response:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Length: 0
Date: Fri, 14 Oct 2016 10:37:55 GMT

Sample error:

500 Internal Server Error
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=utf-8
Content-Language: en
Content-Length: 1111
Date: Fri, 14 Oct 2016 11:14:25 GMT
Connection: close

...

HTTP Status 500 - CGP error [10] [Invalid parameter: Invalid currency code]

...

Profiles management

The SDK is based on profiles, so the Application can handle more than one store or credential at a same time.

Most operations can only be executed if a profile is active. After URMS-SDK is correctly initialized it must create or switch to an existing profile. No profile will be active automatically after restart.

The best workflow would be to follow these steps:

  1. Call UrmsGetProfilesTask to get list of already registered profiles.
  2. Call UrmsCreateProfileTask in the case the profile does not already exist in the output of UrmsGetProfilesTask.
  3. Call UrmsSwitchProfileTask to switch to the profile which is in the list of UrmsGetProfilesTask.
  4. Call UrmsDeleteProfileTask to delete active profile only. It can be used to purge corrupted profiles but it is needed to switch to this profile first.
  5. Call UrmsGetActiveProfileTask to get active profile (switch/create) if needed. This step is optional.

It is not necessary to set the configuration for createProfileTask. It is enough to simply provide the authentication token coming from a store.

Books management

This set of tasks can be used only if a profile is already active.

The best workflow would be to follow these steps:

  1. Call UrmsGetOnlineBooksTask (online mode) or UrmsGetDownloadedBooksTask (offline mode) to get list of books and their CCID codes.
  2. Call UrmsSynchronizeBookshelfTask to synchronise registered books ownership on the server. This task deregisters any ebooks that are registered but no longer owned anymore.
  3. Call UrmsRegisterBookTask to register new book only once and using active appropriate profile. It means the book remains registered after restarting the Application and switching to the appropriate profile. All registered books are in the list of UrmsGetDownloadedBooksTask, so you can decide if this action is needed or not. Since the book is registered then is possible to read it in offline mode.
  4. UrmsDeregisterBookTask is not needed to be called before UrmsDeleteProfileTask because it is done automatically.
  5. Do not forget to call UrmsEvaluateLicenseTask before any attempt to read this book because this task load/refresh license from server. It is also working in offline mode which results in checking local license only (no lag).

The remaining tasks can be used to get details about the book.

  • UrmsGetLendExpiryTask
  • UrmsIsMarlinBookTask
  • UrmsGetContentDetailTask

Bookmark management

This set of tasks can be used only if a profile is already active. The best way for this to happen is to call UrmsGetBookmarksTask after UrmsEvaluateLicenseTask before reading the book.

  • UrmsCreateBookmarkTask
  • UrmsUpdateBookmarkTask
  • UrmsDeleteBookmarkTask
  • UrmsGetBookmarksTask

A default bookmark (hidden for customers) can be used to store last read page. It is useful to jump to this last read page when the customer opens the book again.

Friend to friend operations

This set of tasks can be used only if a profile is already active. There is no workflow tips for this group of tasks.

  • UrmsLendBookTask
  • UrmsGiftBookTask
  • UrmsReturnBookTask
  • UrmsGetbackBookTask
  • UrmsSellBookTask
  • UrmsCancelSellingTask

For general description look at platform-specific documentation and store documentation. See Friend to Friend transactions.

Groups management

This set of tasks can be used only if a profile is already active.

  • UrmsCreateGroupTask
  • UrmsDeleteGroupTask
  • UrmsRenameGroupTask
  • UrmsGetGroupsTask
  • UrmsAddGroupUserTask
  • UrmsRemoveGroupUserTask
  • UrmsAddGroupBookTask
  • UrmsRemoveGroupBookTask

For general description look at platform-specific documentation and store documentation. See User Groups for details on the store-reader features.

Decryption API

The decryption API can be directly invoked from native C++ code. it is stream based and single-threaded, so only one resource can be decrypted at a time.

The marlin_sdk.h header file declares the API and needs to be included in the project.

An eBook must be evaluated at least once by URMSEvaluateLicenseTask before it can be decrypted. We recommend that you always evaluate a license for an eBook before attempting to encrypt that title.

Usage

  1. Create the context. The new instance must be valid during the decryption and is automatically deleted as soon as the block ends (shared_ptr).

MarlinSDK::MarlinContextPtr marlinContext = MarlinSDK::MarlinContext::CreateMarlinContext();

  1. Create a stream instance. Specify the source for the decryption, either a buffer or a file.

MarlinSDK::MarlinStreamPtr sourceMemoryStream = marlinContext->CreateStreamFromBuffer(data, (uint32_t)len);
MarlinSDK::MarlinStreamPtr inStream = marlinContext->CreateStreamFromFile(\content_->file_path());

  1. Create a decryptor instance to create another Marlin stream, providing encrypted data.

MarlinSDK::MarlinStreamPtr outStream = marlinContext->CreateDecryptor(inStream);

Error handling

All errors are automatically returned to the MarlinContext instance. It is enough then to check for the last error, using code like this:
bool isError = marlinContext->GetLastError().IsError();
if (isError) {
std::string errorStr = marlinContext->GetLastError().CodeStr();
}

You can use the error code for tracking bugs reported to Datalogics.

MarlinContext

static MarlinContextPtr CreateMarlinContext() Creates an instance of a Marlin Context.
const MarlinError& GetLastError() Get the last error that occurred.
MarlinStreamPtr CreateStreamFromFile(const std::string &path) Creates an input stream from the given file path.
MarlinStreamPtr CreateStreamFromBuffer(const void *buffer, uint32_t length) Creates an input stream from the given buffer.
MarlinStreamPtr CreateDecryptor(MarlinStreamPtr source) Creates a decryptor instance for the given stream.

MarlinStream

uint32_t GetLength() Get total length of the stream.
bool Seek(uint32_t position) Seek to the position of the stream. @param position starting position @result Return true is success, false otherwise.
uint32_t Tell() Tell position of the stream.
uint32_t Read(void *buffer, uint32_t length) Read data from actual position @param buffer allocated buffer prepared for the output @param length length of allocated buffer @result Return real length of the data written to the output stream / 0 – Error

MarlinError

bool IsError() Identify if it is on error condition.
uint32_t Code() Returns the error code.
const std::string CodeStr() Returns the error message.