Skip to content

Sample codes to generate DRM license token for Doverunner multi-DRM integration

Notifications You must be signed in to change notification settings

doverunner/drm-license-token-sample-python

Repository files navigation

DoveRunner Token Sample - PYTHON (v3.0)

Overview

This repository provides server-side sample code that can generate license token for DoveRunner multi-DRM service. DRM license tokens are used to authenticate license requests in multi-DRM integration workflows.

Here's how a license token works in the DRM license issuance process.

  • When a multi-DRM client tries to play DRM content, the client requests a token to the content service platform to acquire DRM license. The service platform verifies that the user requesting the token has permission to the content, and then generates a token data according to the specification.
  • The service platform can set usage rights and various security policies in the token data. The generated token is delivered to the client as response.
  • When the client requests a DRM license with the token, DoveRunner cloud server validates the token and issues a license.

Documentation


Prerequisites

Language

This works on PYTHON version :

  • 3.13.* and greater

IDE

  • PyCharm
  • conda 24.9.2

Libraries

Option 1: Using Conda (Recommended for cross-platform compatibility)

For Anaconda users, create a virtual environment using environment.yml file and command.

environment.yml file :

# Cross-Platform Conda Environment for ARM64 & x86_64
# ARM64(Apple Silicon)과 x86_64(Linux/macOS Intel) 양쪽에서 호환되는 환경
name: drm_test or other name you want
channels:
  - conda-forge
  - defaults
dependencies:

  - python=3.13.*

  # 도구들(pip, wheel)은 별도 버전 고정 없이 최신 호환 빌드 사용
  # Use the latest compatible builds of tools like pip and wheel without fixing versions
  - pip
  - wheel

  # Certificate 패키지는 arm64에 여러 빌드가 있으므로 버전 고정 해제
  # Unpin certificate-related packages since multiple builds exist for arm64
  - ca-certificates
  - certifi

  # OpenSSL은 1.1.1k 이상 빌드가 있으므로 최소 요구조건만 명시
  # Specify minimum required version for OpenSSL (1.1.1k or higher available)
  - openssl>=1.1.1k

  # pycrypto는 arm64에서 빌드가 제공되지 않으므로 pycryptodome으로 교체
  # Replace pycrypto with pycryptodome as pycrypto is unavailable on arm64
  - pycryptodome

  - pytz
  - setuptools
  - sqlite

prefix: {{ conda_prefix }}

command :

conda env create -f environment.yml

Option 2: Using pip

If you prefer using pip instead of conda:

pip install pycryptodome pytz



Directories

dir description
doverunner
/config configuration module for policy
/exception exception package
/sample make token sample @client_test.py
/token source directory

Guide

Go to DoveRunner Docs for Policy Json Specification and figure out which specification to use.

How to get token

  1. Configuration Setup (Required)

    Before running make_token.py, create a configuration file with your DoveRunner credentials:

    # Copy the example configuration file to project root
    cp config.ini.example config.ini
    
    # Edit config.ini and fill in your actual values
    # Replace placeholders with your DoveRunner credentials

    The config.ini file (in project root) should contain:

    [drm]
    site_id = YOUR_SITE_ID
    site_key = YOUR_SITE_KEY
    access_key = YOUR_ACCESS_KEY
    user_id = tester-user
    content_id = YOUR_CONTENT_ID

    Note: The config.ini file is gitignored to prevent accidental commits of sensitive credentials.

    After configuration, run: python -m doverunner.sample.make_token

  2. Before get token, you need to set up policy.

    from doverunner_drm_token_policy import DoveRunnerDrmTokenPolicy as Policy
    
    policy = Policy()
    
    def set_policy():
        set_playback_policy()
        set_security_policy()
        set_external_key()
        
        policy \
            .playback(playback) \
            .security(security) \
            .external(external)
  3. As you can see above, you need to decide whether to set playback, security, or external.

    If you want to set up all policies,

    from doverunner_drm_token_policy import PlaybackPolicy
    from doverunner_drm_token_policy import SecurityPolicy
    from doverunner_drm_token_policy import ExternalKey
    
    playback = PlaybackPolicy()
    security = SecurityPolicy()
    external = ExternalKey()
    
    
    def set_playback_policy():
        playback \
            .allowed_track_types(allowed_track_types.SD_ONLY) \
            .persistent(False)
            
    def set_security_policy():
        security.track_type(track_type.ALL) \
             .widevine(Widevine()
                       .security_level(1)
                       .required_hdcp_version('HDCP_NONE')
                       .required_cgms_flags('CGMS_NONE')
                       .override_device_revocation(False)) \
             .playready(Playready()
                        .security_level(150)
                        .digital_video_protection_level(100)
                        .analog_video_protection_level(100)
                        .digital_audio_protection_level(100)
                        ) \
             .fairplay(Fairplay()
                       .hdcp_enforcement(-1)
                       .allow_airplay(True)
                       .allow_av_adapter(True)) \
             .ncg(Ncg()
                  .allow_mobile_abnormal_device(True)
                  .allow_external_display(True)
                  .control_hdcp(0))
    
    def set_external_key():
        """
        ### set mpeg_cecn | hls_aes | ncg
        """
        hls_aes_list = [
            HlsAes(track_type.SD,
                   '<key_id>',
                   '<key>'),
            HlsAes(track_type.HD,
                   '<key_id>',
                   '<key>'),
            HlsAes(track_type.UHD1,
                   '<key_id>',
                   '<key>'),
            HlsAes(track_type.UHD2,
                   '<key_id>',
                   '<key>')
        ]
    
        external \
            .mpeg_cenc(MpegCenc(track_type.HD,
                                '<key_id>',
                                '<key>',
                                '<iv>')) \
            .mpeg_cenc(MpegCenc(track_type.UHD1,
                                '<key_id>',
                                '<key>',
                                '<iv>')) \
            .mpeg_cenc(MpegCenc(track_type.UHD2,
                                '<key_id>',
                                '<key>',
                                '<iv>')) \
            .hls_aes(hls_aes_list) \
            .ncg(Ncg(track_type.ALL_VIDEO,
                     '<cek>'))
  4. Import DoveRunnerDrmTokenClient and load configuration

    from doverunner_drm_token_client import DoveRunnerDrmTokenClient as Token
    from doverunner.config import response_format
    import configparser
    import os
    
    def load_config():
        """Load configuration from config.ini file in project root."""
        project_root = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
        config_path = os.path.join(project_root, 'config.ini')
    
        config = configparser.ConfigParser()
        config.read(config_path)
    
        return {
            'site_id': config.get('drm', 'site_id'),
            'site_key': config.get('drm', 'site_key'),
            'access_key': config.get('drm', 'access_key'),
            'user_id': config.get('drm', 'user_id'),
            'content_id': config.get('drm', 'content_id')
        }
    
    def set_drm_token():
        config = load_config()  # Load from config.ini
        set_policy()
        token = Token()\
            .widevine()\
            .site_id(config['site_id'])\
            .site_key(config['site_key'])\
            .access_key(config['access_key'])\
            .user_id(config['user_id'])\
            .cid(config['content_id'])\
            .policy(policy)\
            .response_format(response_format.ORIGINAL)
    
        token.execute()
  5. Make encrypted token !

    try:
        set_drm_token()
    except DoveRunnerTokenException as p:
        print(p)

    DoveRunnerTokenException will arise if there are minor mistakes when created. The result will return JSON with an error_code and error_message. Follow the comment and fix the bugs.

    For example,

    {
        "error_code": "1048",
        "error_message": "Token err : The response_format should be in type of RESPONSE_FORMAT in [doverunner.config.response_format] module"
    }

    If you want to see All the error codes and error messages you would get, see the error_list in doverunner\excepion\doverunner_tokne_exception.py module.

We hope this instruction would be helpful to generate DRM License Token to request DoveRunner Multi-DRM Cloud Server and get the License issued from.

Error Messages

Error Code Error Messages
1000 Token err : The userId is Required
1001 Token err : The cId is Required
1002 Token err : The siteId is Required
1003 Token err : The accessKey is Required
1004 Token err : The siteKey is Required
1005 Token err : The policy is Required
1006 Policy Err : The playback_policy should be an instance of PlaybackPolicy
1007 Policy Err : The security_policy should be an instance of SecurityPolicy or List[SecurityPolicy]
1008 Policy Err : The external_key should be an instance of ExternalKey
1009 PlaybackPolicy : The persistent should be Boolean
1010 PlaybackPolicy : The license_duration should be Integer
1011 PlaybackPolicy : The expireDate time format should be 'YYYY-MM-DD'T'HH:mm:ss'Z'
1012 PlaybackPolicy : The allowed_track_types value should be in allowed_track_types module
1013 SecurityPolicy: The track_type should be in type of TRACK_TYPE
in doverunner.config.track_type module
1014 SecurityPolicy: The widevine should be an instance of SecurityPolicyWidevine
1015 SecurityPolicy: The playready should be an instance of SecurityPolicyPlayready
1016 SecurityPolicy: The fairplay should be an instance of SecurityPolicyFairplay
1017 SecurityPolicy: The ncg should be an instance of SecurityPolicyNcg
1018 ExternalKey: The ExternalKey Should be filled if called
1019 ExternalKey: The MpegCenc should be an instance of MpegCenc or List[MpegCenc]
1020 ExternalKey: The HlsAes should be an instance of HlsAes or List[HlsAes]
1021 ExternalKey: The Ncg should be an instance of Ncg
1022 SecurityPolicyWidevine: The security_level should be in type of SECURITY_LEVEL
in doverunner.config.widevine.security_level module
1023 SecurityPolicyWidevine: The required_hdcp_version should be in type of REQUIRED_HDCP_VERSION
in doverunner.config.widevine.required_hdcp_version module
1024 SecurityPolicyWidevine: The required_cgms_flagsshould be in type of REQUIRED_CGMS_FLAGS
in doverunner.config.widevine.required_cgms_flags module
1025 SecurityPolicyWidevine: The disable_analog_output should be Boolean
1026 SecurityPolicyWidevine: The hdcp_srm_rule should be in type of HDCP_SRM_RULE
in doverunner.config.widevine.hdcp_srm_rule module
1027 SecurityPolicyPlayready: The security_level should be in type of SECURITY_LEVEL
in doverunner.config.playready.security_level module
1028 SecurityPolicyPlayready: The digital_video_protection_level should be in type of DIGITAL_VIDEO_PROTECTION_LEVEL
in doverunner.config.playready.digital_video_protection module
1029 SecurityPolicyPlayready: The analog_video_protection_level should be in type of ANALOG_VIDEO_PROTECTION_LEVEL
in doverunner.config.playready.analog_video_protection module
1030 SecurityPolicyPlayready: The digital_audio_protection_level should be in type of DIGITAL_AUDIO_PROTECTION
in doverunner.config.playready.digital_audio_protection module
1032 SecurityPolicyPlayready: The require_hdcp_type_1 should be Boolean
1033 SecurityPolicyFairplay: The hdcp_enforcement should be in type of FAIRPLAY_HDCP_ENFORCEMENT
in doverunner.config.fairplay_hdcp_enforcement module
1034 SecurityPolicyFairplay: The allow_airplay should be Boolean
1035 SecurityPolicyFairplay: The allow_av_adapter should be Boolean
1036 SecurityPolicyNcg: The allow_mobile_abnormal_device should be Boolean
1037 SecurityPolicyNcg: The allow_external_display should be Boolean
1038 SecurityPolicyNcg: The control_hdcp should be in type of CONTROL_HDCP
in doverunner.config.ncg_control_hdcp module
1039 ExternalKeyMpegCenc: The track_type should be in type of TRACK_TYPE
in doverunner.config.track_type module
1040 ExternalKeyMpegCenc : The key_id should be 16byte hex String
1041 ExternalKeyMpegCenc : The key should be 16byte hex String
1042 ExternalKeyMpegCenc : The iv should be 16byte hex String
1043 ExternalKeyHlsAes: The track_type should be in type of TRACK_TYPE
in doverunner.config.track_type module
1044 ExternalKeyHlsAes : The key should be 16byte hex String
1045 ExternalKeyHlsAes : The iv should be 16byte hex String
1046 ExternalKeyNcg : The track_type should be in type of TRACK_TYPE
in doverunner.config.track_type module
1047 ExternalKeyNcg : The Cek should be 32byte hex String
1048 Token err : The response_format should be in type of RESPONSE_FORMAT
in doverunner.config.response_format module
1049 PlaybackPolicy : The rental_duration should be Integer
1050 PlaybackPolicy : The playback_duration should be Integer
1051 SecurityPolicyWidevine: The override_device_revocation should be Boolean
1052 ExternalKeyHlsAes : The key_id should be 16byte hex String
1053 PlaybackPolicy : The max_stream_per_user should be Integer
1054 SecurityPolicyWidevine : The enable_license_cipher should be Boolean
1055 Token err : The key_rotation should be Boolean

Support

If you have any questions or issues with the token sample, please create a ticket at DoveRunner Helpdesk website.

About

Sample codes to generate DRM license token for Doverunner multi-DRM integration

Topics

Resources

Stars

Watchers

Forks

Contributors 6

Languages