diff --git a/.bumpversion.cfg b/.bumpversion.cfg
index 6106019..a9a3316 100644
--- a/.bumpversion.cfg
+++ b/.bumpversion.cfg
@@ -1,5 +1,5 @@
[bumpversion]
-current_version = 3.10.0
+current_version = 3.11.0
commit = True
tag = True
diff --git a/.gitignore b/.gitignore
index f14b9eb..6924f93 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,6 +33,7 @@ pip-delete-this-directory.txt
.coverage
.cache
coverage.xml
+htmlcov/
# Translations
*.mo
@@ -55,3 +56,6 @@ env/
# Pyenv
.python-version
+
+# Credentials
+credentials/
\ No newline at end of file
diff --git a/CHANGES.md b/CHANGES.md
index 9c453ea..b7109a0 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,3 +1,8 @@
+# Release 3.11.0
+- OpenTok SDK now accepts Vonage credentials so it's possible to use the existing OpenTok SDK with the Vonage Video API
+- Add additional headers to some requests
+- Internal changes to the `Opentok.create_session` method
+
# Release 3.10.0
- Add new `max_bitrate` option for archives
- Change to create JWTs by default in the `Client.generate_token` method. T1 tokens can still be created by setting `use_jwt=False` when generating a token.
diff --git a/Makefile b/Makefile
index 01ecd3b..1d3f861 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@ clean:
rm -rf dist build
coverage:
- pytest -v --cov
+ pytest -v --cov=opentok
coverage html
test:
diff --git a/opentok/opentok.py b/opentok/opentok.py
index 7bcf3f4..667067b 100644
--- a/opentok/opentok.py
+++ b/opentok/opentok.py
@@ -1,4 +1,5 @@
from datetime import datetime # generate_token
+import re
from typing import List, Optional # imports List, Optional type hint
import calendar # generate_token
import base64 # generate_token
@@ -7,6 +8,7 @@
import hmac # _sign_string
import hashlib
from typing import List
+import uuid
import requests # create_session, archiving
import json # archiving
import platform # user-agent
@@ -19,7 +21,7 @@
# compat
-from six.moves.urllib.parse import urlencode
+from urllib.parse import urlencode
from six import text_type, u, b, PY3
from enum import Enum
@@ -111,6 +113,11 @@ class ArchiveModes(Enum):
class Client(object):
"""Use this SDK to create tokens and interface with the server-side portion
of the Opentok API.
+
+ You can also interact with this client object with Vonage credentials. Instead of passing
+ on OpenTok API key and secret, you can pass in a Vonage application ID and private key,
+ e.g. api_key=VONAGE_APPLICATION_ID, api_secret=VONAGE_PRIVATE_KEY. You do not need to set the API
+ URL differently, the SDK will set this for you.
"""
TOKEN_SENTINEL = "T1=="
@@ -124,11 +131,25 @@ def __init__(
timeout=None,
app_version=None,
):
+
+ if isinstance(api_secret, (str, bytes)) and re.search(
+ "[.][a-zA-Z0-9_]+$", api_secret
+ ):
+ # We have a private key so we assume we are using Vonage credentials
+ self._using_vonage = True
+ self._api_url = 'https://video.api.vonage.com'
+ with open(api_secret, "rb") as key_file:
+ self.api_secret = key_file.read()
+ else:
+ # We are using OpenTok credentials
+ self._using_vonage = False
+ self.api_secret = api_secret
+ self._api_url = api_url
+
self.api_key = str(api_key)
- self.api_secret = api_secret
self.timeout = timeout
self._proxies = None
- self.endpoints = Endpoints(api_url, self.api_key)
+ self.endpoints = Endpoints(self._api_url, self.api_key)
self._app_version = __version__ if app_version == None else app_version
self._user_agent = (
f"OpenTok-Python-SDK/{self.app_version} python/{platform.python_version()}"
@@ -306,14 +327,13 @@ def generate_token(
if use_jwt:
payload = {}
- payload['iss'] = self.api_key
- payload['ist'] = 'project'
+
+ payload['session_id'] = session_id
+ payload['role'] = role.value
payload['iat'] = now
payload["exp"] = expire_time
- payload['nonce'] = random.randint(0, 999999)
- payload['role'] = role.value
payload['scope'] = 'session.connect'
- payload['session_id'] = session_id
+
if initial_layout_class_list:
payload['initial_layout_class_list'] = (
initial_layout_class_list_serialized
@@ -321,9 +341,27 @@ def generate_token(
if data:
payload['connection_data'] = data
- headers = {'alg': 'HS256', 'typ': 'JWT'}
+ if not self._using_vonage:
+ payload['iss'] = self.api_key
+ payload['ist'] = 'project'
+ payload['nonce'] = random.randint(0, 999999)
+
+ headers = {'alg': 'HS256', 'typ': 'JWT'}
- token = encode(payload, self.api_secret, algorithm="HS256", headers=headers)
+ token = encode(
+ payload, self.api_secret, algorithm="HS256", headers=headers
+ )
+ else:
+ payload['application_id'] = self.api_key
+ payload['jti'] = str(uuid.uuid4())
+ payload['subject'] = 'video'
+ payload['acl'] = {'paths': {'/session/**': {}}}
+
+ headers = {'alg': 'RS256', 'typ': 'JWT'}
+
+ token = encode(
+ payload, self.api_secret, algorithm="RS256", headers=headers
+ )
return token
@@ -500,39 +538,54 @@ def create_session(
"POST to %r with params %r, headers %r, proxies %r",
self.endpoints.get_session_url(),
options,
- self.get_headers(),
+ self.get_json_headers(),
self.proxies,
)
- response = requests.post(
- self.endpoints.get_session_url(),
- data=options,
- headers=self.get_headers(),
- proxies=self.proxies,
- timeout=self.timeout,
- )
+ if not self._using_vonage:
+ response = requests.post(
+ self.endpoints.get_session_url(),
+ data=options,
+ headers=self.get_headers(),
+ proxies=self.proxies,
+ timeout=self.timeout,
+ )
+ else:
+ headers = self.get_headers()
+ response = requests.post(
+ self.endpoints.get_session_url(),
+ data=options,
+ headers=headers,
+ proxies=self.proxies,
+ timeout=self.timeout,
+ )
response.encoding = "utf-8"
-
if response.status_code == 403:
raise AuthError("Failed to create session, invalid credentials")
if not response.content:
raise RequestError()
- dom = xmldom.parseString(response.content.decode("utf-8"))
except Exception as e:
raise RequestError("Failed to create session: %s" % str(e))
try:
- error = dom.getElementsByTagName("error")
- if error:
- error = error[0]
- raise AuthError(
- "Failed to create session (code=%s): %s"
- % (
- error.attributes["code"].value,
- error.firstChild.attributes["message"].value,
+ content_type = response.headers["Content-Type"]
+ # Legacy behaviour
+ if content_type != "application/json":
+ dom = xmldom.parseString(response.content.decode("utf-8"))
+ error = dom.getElementsByTagName("error")
+ if error:
+ error = error[0]
+ raise AuthError(
+ "Failed to create session (code=%s): %s"
+ % (
+ error.attributes["code"].value,
+ error.firstChild.attributes["message"].value,
+ )
)
+ session_id = (
+ dom.getElementsByTagName("session_id")[0].childNodes[0].nodeValue
)
-
- session_id = dom.getElementsByTagName("session_id")[0].childNodes[0].nodeValue
+ else:
+ session_id = response.json()[0]["session_id"]
return Session(
self,
session_id,
@@ -546,12 +599,19 @@ def create_session(
def get_headers(self):
"""For internal use."""
+ if not self._using_vonage:
+ return {
+ "User-Agent": "OpenTok-Python-SDK/"
+ + self.app_version
+ + " python/"
+ + platform.python_version(),
+ "X-OPENTOK-AUTH": self._create_jwt_auth_header(),
+ "Accept": "application/json",
+ }
return {
- "User-Agent": "OpenTok-Python-SDK/"
- + self.app_version
- + " python/"
- + platform.python_version(),
- "X-OPENTOK-AUTH": self._create_jwt_auth_header(),
+ "User-Agent": self.user_agent + " OpenTok-With-Vonage-API-Backend",
+ "Authorization": "Bearer " + self._create_jwt_auth_header(),
+ "Accept": "application/json",
}
def headers(self):
@@ -1859,13 +1919,13 @@ def stop_render(self, render_id):
logger.debug(
"DELETE to %r with headers %r, proxies %r",
self.endpoints.get_render_url(render_id=render_id),
- self.get_headers(),
+ self.get_json_headers(),
self.proxies,
)
response = requests.delete(
self.endpoints.get_render_url(render_id=render_id),
- headers=self.get_headers(),
+ headers=self.get_json_headers(),
proxies=self.proxies,
timeout=self.timeout,
)
@@ -1896,14 +1956,14 @@ def list_renders(self, offset=0, count=50):
logger.debug(
"GET to %r with headers %r, params %r, proxies %r",
self.endpoints.get_render_url(),
- self.get_headers(),
+ self.get_json_headers(),
query_params,
self.proxies,
)
response = requests.get(
self.endpoints.get_render_url(),
- headers=self.get_headers(),
+ headers=self.get_json_headers(),
params=query_params,
proxies=self.proxies,
timeout=self.timeout,
@@ -2090,14 +2150,21 @@ def _sign_string(self, string, secret):
def _create_jwt_auth_header(self):
payload = {
"ist": "project",
- "iss": self.api_key,
"iat": int(time.time()), # current time in unix time (seconds)
"exp": int(time.time())
+ (60 * self._jwt_livetime), # 3 minutes in the future (seconds)
- "jti": "{0}".format(0, random.random()),
}
- return encode(payload, self.api_secret, algorithm="HS256")
+ if not self._using_vonage:
+ payload["iss"] = self.api_key
+ payload["jti"] = str(random.random())
+ return encode(payload, self.api_secret, algorithm="HS256")
+
+ payload["application_id"] = self.api_key
+ payload["jti"] = str(uuid.uuid4())
+ headers = {"typ": "JWT", "alg": "RS256"}
+
+ return encode(payload, self.api_secret, algorithm='RS256', headers=headers)
def mute_all(
self, session_id: str, excludedStreamIds: Optional[List[str]]
@@ -2127,7 +2194,7 @@ def mute_all(
options = {"active": True, "excludedStreams": []}
response = requests.post(
- url, headers=self.get_headers(), data=json.dumps(options)
+ url, headers=self.get_json_headers(), data=json.dumps(options)
)
if response:
@@ -2164,7 +2231,7 @@ def disable_force_mute(self, session_id: str) -> requests.Response:
url = self.endpoints.get_mute_all_url(session_id)
response = requests.post(
- url, headers=self.get_headers(), data=json.dumps(options)
+ url, headers=self.get_json_headers(), data=json.dumps(options)
)
try:
@@ -2198,7 +2265,7 @@ def mute_stream(self, session_id: str, stream_id: str) -> requests.Response:
if stream_id:
url = self.endpoints.get_stream_url(session_id, stream_id) + "/mute"
- response = requests.post(url, headers=self.get_headers())
+ response = requests.post(url, headers=self.get_json_headers())
if response:
return response
@@ -2315,7 +2382,7 @@ def mute_all(
options = {"active": True, "excludedStreams": []}
response = requests.post(
- url, headers=self.get_headers(), data=json.dumps(options)
+ url, headers=self.get_json_headers(), data=json.dumps(options)
)
if response:
@@ -2350,7 +2417,7 @@ def disable_force_mute(self, session_id: str) -> requests.Response:
url = self.endpoints.get_mute_all_url(session_id)
response = requests.post(
- url, headers=self.get_headers(), data=json.dumps(options)
+ url, headers=self.get_json_headers(), data=json.dumps(options)
)
try:
@@ -2382,7 +2449,7 @@ def mute_stream(self, session_id: str, stream_id: str) -> requests.Response:
if stream_id:
url = self.endpoints.get_stream_url(session_id, stream_id) + "/mute"
- response = requests.post(url, headers=self.get_headers())
+ response = requests.post(url, headers=self.get_json_headers())
if response:
return response
diff --git a/opentok/version.py b/opentok/version.py
index 9650d1a..bdb2381 100644
--- a/opentok/version.py
+++ b/opentok/version.py
@@ -1,3 +1,3 @@
# see: http://legacy.python.org/dev/peps/pep-0440/#public-version-identifiers
-__version__ = "3.10.0"
+__version__ = "3.11.0"
diff --git a/tests/fake_data/dummy_private_key.txt b/tests/fake_data/dummy_private_key.txt
new file mode 100644
index 0000000..163ff36
--- /dev/null
+++ b/tests/fake_data/dummy_private_key.txt
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDQdAHqJHs/a+Ra
+2ubvSd1vz/aWlJ9BqnMUtB7guTlyggdENAbleIkzep6mUHepDJdQh8Qv6zS3lpUe
+K0UkDfr1/FvsvxurGw/YYPagUEhP/HxMbs2rnQTiAdWOT+Ux9vPABoyNYvZB90xN
+IVhBDRWgkz1HPQBRNjFcm3NOol83h5Uwp5YroGTWx+rpmIiRhQj3mv6luk102d95
+4ulpPpzcYWKIpJNdclJrEkBZaghDZTOpbv79qd+ds9AVp1j8i9cG/owBJpsJWxfw
+StMDpNeEZqopeQWmA121sSEsxpAbKJ5DA7F/lmckx74sulKHX1fDWT76cRhloaEQ
+VmETdj0VAgMBAAECggEAZ+SBtchz8vKbsBqtAbM/XcR5Iqi1TR2eWMHDJ/65HpSm
++XuyujjerN0e6EZvtT4Uxmq8QaPJNP0kmhI31hXvsB0UVcUUDa4hshb1pIYO3Gq7
+Kr8I29EZB2mhndm9Ii9yYhEBiVA66zrNeR225kkWr97iqjhBibhoVr8Vc6oiqcIP
+nFy5zSFtQSkhucaPge6rW00JSOD3wg2GM+rgS6r22t8YmqTzAwvwfil5pQfUngal
+oywqLOf6CUYXPBleJc1KgaIIP/cSvqh6b/t25o2VXnI4rpRhtleORvYBbH6K6xLa
+OWgg6B58T+0/QEqtZIAn4miYtVCkYLB78Ormc7Q9ewKBgQDuSytuYqxdZh/L/RDU
+CErFcNO5I1e9fkLAs5dQEBvvdQC74+oA1MsDEVv0xehFa1JwPKSepmvB2UznZg9L
+CtR7QKMDZWvS5xx4j0E/b+PiNQ/tlcFZB2UZ0JwviSxdd7omOTscq9c3RIhFHar1
+Y38Fixkfm44Ij/K3JqIi2v2QMwKBgQDf8TYOOmAr9UuipUDxMsRSqTGVIY8B+aEJ
+W+2aLrqJVkLGTRfrbjzXWYo3+n7kNJjFgNkltDq6HYtufHMYRs/0PPtNR0w0cDPS
+Xr7m2LNHTDcBalC/AS4yKZJLNLm+kXA84vkw4qiTjc0LSFxJkouTQzkea0l8EWHt
+zRMv/qYVlwKBgBaJOWRJJK/4lo0+M7c5yYh+sSdTNlsPc9Sxp1/FBj9RO26JkXne
+pgx2OdIeXWcjTTqcIZ13c71zhZhkyJF6RroZVNFfaCEcBk9IjQ0o0c504jq/7Pc0
+gdU9K2g7etykFBDFXNfLUKFDc/fFZIOskzi8/PVGStp4cqXrm23cdBqNAoGBAKtf
+A2bP9ViuVjsZCyGJIAPBxlfBXpa8WSe4WZNrvwPqJx9pT6yyp4yE0OkVoJUyStaZ
+S5M24NocUd8zDUC+r9TP9d+leAOI+Z87MgumOUuOX2mN2kzQsnFgrrsulhXnZmSx
+rNBkI20HTqobrcP/iSAgiU1l/M4c3zwDe3N3A9HxAoGBAM2hYu0Ij6htSNgo/WWr
+IEYYXuwf8hPkiuwzlaiWhD3eocgd4S8SsBu/bTCY19hQ2QbBPaYyFlNem+ynQyXx
+IOacrgIHCrYnRCxjPfFF/MxgUHJb8ZoiexprP/FME5p0PoRQIEFYa+jVht3hT5wC
+9aedWufq4JJb+akO6MVUjTvs
+-----END PRIVATE KEY-----
diff --git a/tests/fake_data/dummy_public_key.txt b/tests/fake_data/dummy_public_key.txt
new file mode 100644
index 0000000..a171508
--- /dev/null
+++ b/tests/fake_data/dummy_public_key.txt
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0HQB6iR7P2vkWtrm70nd
+b8/2lpSfQapzFLQe4Lk5coIHRDQG5XiJM3qeplB3qQyXUIfEL+s0t5aVHitFJA36
+9fxb7L8bqxsP2GD2oFBIT/x8TG7Nq50E4gHVjk/lMfbzwAaMjWL2QfdMTSFYQQ0V
+oJM9Rz0AUTYxXJtzTqJfN4eVMKeWK6Bk1sfq6ZiIkYUI95r+pbpNdNnfeeLpaT6c
+3GFiiKSTXXJSaxJAWWoIQ2UzqW7+/anfnbPQFadY/IvXBv6MASabCVsX8ErTA6TX
+hGaqKXkFpgNdtbEhLMaQGyieQwOxf5ZnJMe+LLpSh19Xw1k++nEYZaGhEFZhE3Y9
+FQIDAQAB
+-----END PUBLIC KEY-----
diff --git a/tests/helpers.py b/tests/helpers.py
index 5cd4a91..c314520 100644
--- a/tests/helpers.py
+++ b/tests/helpers.py
@@ -26,7 +26,7 @@ def token_decoder(token: str, secret: str = None):
return token_data
encoded = token.replace('Bearer ', '').strip()
- return decode(encoded, secret, algorithms='HS256')
+ return decode(encoded, secret, algorithms=['HS256', 'RS256'])
def token_signature_validator(token, secret):
diff --git a/tests/test_session_creation.py b/tests/test_session_creation.py
index dc65493..e7f2565 100644
--- a/tests/test_session_creation.py
+++ b/tests/test_session_creation.py
@@ -1,7 +1,9 @@
+from time import time
+from jwt import decode
import pytest
import unittest
from six import u, b
-from six.moves.urllib.parse import parse_qs
+from urllib.parse import parse_qs
from expects import *
import httpretty
from .validate_jwt import validate_jwt_header
@@ -28,11 +30,9 @@ def test_create_default_session(self):
httpretty.register_uri(
httpretty.POST,
u("https://api.opentok.com/session/create"),
- body=u(
- '1_MX4xMjM0NTZ-fk1vbiBNYXIgMTcgMDA6NDE6MzEgUERUIDIwMTR-MC42ODM3ODk1MzQ0OTQyODA4fg123456Mon Mar 17 00:41:31 PDT 2014'
- ),
+ body='[{"session_id":"1_MX40NzY2NTk3MX5-MTczOTUzODg5NDk1OX5ROW1jWEcxUXJOM1RJWXU4eStwcHgvZ3N-UH5-","project_id":"47665971","partner_id":"47665971","create_dt":"Fri Feb 14 05:14:54 PST 2025","session_status":null,"status_invalid":null,"media_server_hostname":null,"messaging_server_url":null,"messaging_url":null,"symphony_address":null,"properties":null,"ice_server":null,"session_segment_id":"9c5fdd5b-7f5b-408f-8633-db95d0054fad","ice_servers":null,"ice_credential_expiration":86100}]',
status=200,
- content_type=u("text/xml"),
+ content_type=u("application/json"),
)
session = self.opentok.create_session()
@@ -54,7 +54,79 @@ def test_create_default_session(self):
have_property(
u("session_id"),
u(
- "1_MX4xMjM0NTZ-fk1vbiBNYXIgMTcgMDA6NDE6MzEgUERUIDIwMTR-MC42ODM3ODk1MzQ0OTQyODA4fg"
+ "1_MX40NzY2NTk3MX5-MTczOTUzODg5NDk1OX5ROW1jWEcxUXJOM1RJWXU4eStwcHgvZ3N-UH5-"
+ ),
+ )
+ )
+ expect(session).to(have_property(u("media_mode"), MediaModes.relayed))
+ expect(session).to(have_property(u("location"), None))
+ expect(session).to(have_property(u("e2ee"), False))
+
+ @httpretty.activate
+ def test_create_default_vonage_session(self):
+ httpretty.register_uri(
+ httpretty.POST,
+ u("https://video.api.vonage.com/session/create"),
+ body="""
+ [
+ {
+ "session_id": "1_MX4yOWY3NjBmOC03Y2UxLTQ2YzktYWRlMy1mMmRlZGVlNGVkNWZ-fjE3MjY0NjI1ODg2NDd-MTF4TGExYmJoelBlR1FHbVhzbWd4STBrfn5-",
+ "project_id": "29f760f8-7ce1-46c9-ade3-f2dedee4ed5f",
+ "partner_id": "29f760f8-7ce1-46c9-ade3-f2dedee4ed5f",
+ "create_dt": "Sun Sep 15 21:56:28 PDT 2024",
+ "session_status": null,
+ "status_invalid": null,
+ "media_server_hostname": null,
+ "messaging_server_url": null,
+ "messaging_url": null,
+ "symphony_address": null,
+ "properties": null,
+ "ice_server": null,
+ "session_segment_id": "35308566-4012-4c1e-90f7-cc15b5a390fe",
+ "ice_servers": null,
+ "ice_credential_expiration": 86100
+ }
+ ]""",
+ status=200,
+ content_type="application/json",
+ )
+
+ self.api_secret = './tests/fake_data/dummy_private_key.txt'
+ vonage_wrapper = Client(self.api_key, self.api_secret)
+ session = vonage_wrapper.create_session()
+
+ public_key = ""
+ with open('./tests/fake_data/dummy_public_key.txt', 'r') as file:
+ public_key = file.read()
+
+ decoded_jwt = decode(
+ httpretty.last_request().headers[u("Authorization")].split(None, 1)[1],
+ public_key,
+ algorithms=["RS256"],
+ )
+
+ expect(decoded_jwt["application_id"]).to(equal(vonage_wrapper.api_key))
+ expect(decoded_jwt["ist"]).to(equal("project"))
+ expect(decoded_jwt["exp"]).to(be_above(time()))
+
+ expect(httpretty.last_request().headers[u("user-agent")]).to(
+ equal(
+ u("OpenTok-Python-SDK/")
+ + __version__
+ + " python/"
+ + platform.python_version()
+ + " OpenTok-With-Vonage-API-Backend"
+ )
+ )
+ body = parse_qs(httpretty.last_request().body)
+ expect(body).to(have_key(b("p2p.preference"), [b("enabled")]))
+ expect(body).to(have_key(b("archiveMode"), [b("manual")]))
+ expect(session).to(be_a(Session))
+ expect(session).to(
+ have_property(
+ u("session_id"),
+ u(
+ "1_MX4yOWY3NjBmOC03Y2UxLTQ2YzktYWRlMy1mMmRlZGVlNGVkNWZ-fjE3MjY0NjI1ODg2NDd-MTF4TGExYmJoelBlR1FHbVhzbWd4STBrfn5-"
),
)
)
@@ -67,11 +139,9 @@ def test_create_routed_session(self):
httpretty.register_uri(
httpretty.POST,
u("https://api.opentok.com/session/create"),
- body=u(
- '1_MX4xMjM0NTZ-fk1vbiBNYXIgMTcgMDA6NDE6MzEgUERUIDIwMTR-MC42ODM3ODk1MzQ0OTQyODA4fg123456Mon Mar 17 00:41:31 PDT 2014'
- ),
+ body='[{"session_id":"1_MX40NzY2NTk3MX5-MTczOTUzODg5NDk1OX5ROW1jWEcxUXJOM1RJWXU4eStwcHgvZ3N-UH5-","project_id":"47665971","partner_id":"47665971","create_dt":"Fri Feb 14 05:14:54 PST 2025","session_status":null,"status_invalid":null,"media_server_hostname":null,"messaging_server_url":null,"messaging_url":null,"symphony_address":null,"properties":null,"ice_server":null,"session_segment_id":"9c5fdd5b-7f5b-408f-8633-db95d0054fad","ice_servers":null,"ice_credential_expiration":86100}]',
status=200,
- content_type=u("text/xml"),
+ content_type=u("application/json"),
)
session = self.opentok.create_session(media_mode=MediaModes.routed)
@@ -88,7 +158,7 @@ def test_create_routed_session(self):
have_property(
u("session_id"),
u(
- "1_MX4xMjM0NTZ-fk1vbiBNYXIgMTcgMDA6NDE6MzEgUERUIDIwMTR-MC42ODM3ODk1MzQ0OTQyODA4fg"
+ "1_MX40NzY2NTk3MX5-MTczOTUzODg5NDk1OX5ROW1jWEcxUXJOM1RJWXU4eStwcHgvZ3N-UH5-"
),
)
)
diff --git a/tests/test_stream.py b/tests/test_stream.py
index c568724..4b32fec 100644
--- a/tests/test_stream.py
+++ b/tests/test_stream.py
@@ -1,8 +1,7 @@
import unittest
-from six import text_type, u, b, PY2, PY3
+from six import u
from opentok import Client, Stream, StreamList, __version__, SetStreamClassError
import httpretty
-import json
import textwrap
from expects import *
@@ -163,7 +162,7 @@ def test_get_stream_list(self):
@httpretty.activate
def test_set_stream_class_lists(self):
- """ Test set stream class functionality """
+ """Test set stream class functionality"""
payload = [
{
"id": "7b09ec3c-26f9-43d7-8197-f608f13d4fb6",
@@ -197,7 +196,7 @@ def test_set_stream_class_lists(self):
@httpretty.activate
def test_set_stream_class_lists_throws_exception(self):
- """ Test invalid request in set stream class list """
+ """Test invalid request in set stream class list"""
# invalid payload
payload = [{"id": "7b09ec3c-26f9-43d7-8197-f608f13d4fb6"}]
diff --git a/tests/test_token_generation.py b/tests/test_token_generation.py
index 07e943a..e9e7b9d 100644
--- a/tests/test_token_generation.py
+++ b/tests/test_token_generation.py
@@ -1,10 +1,9 @@
import pytest
import unittest
-from six import text_type, u, PY2, PY3
+from six import text_type, u
import time
import datetime
import calendar
-import pytz
from opentok import Client, Roles, OpenTokException
@@ -31,6 +30,17 @@ def test_generate_plain_token_jwt(self):
assert isinstance(token, text_type)
assert token_decoder(token, self.api_secret)[u("session_id")] == self.session_id
+ def test_generate_plain_token_jwt_vonage_wrapper(self):
+ self.api_secret = './tests/fake_data/dummy_private_key.txt'
+ vonage_wrapper = Client(self.api_key, self.api_secret)
+ public_key = ""
+ with open('./tests/fake_data/dummy_public_key.txt', 'r') as file:
+ public_key = file.read()
+
+ token = vonage_wrapper.generate_token(self.session_id)
+ assert isinstance(token, text_type)
+ assert token_decoder(token, public_key)[u("session_id")] == self.session_id
+
def test_generate_role_token(self):
token = self.opentok.generate_token(self.session_id, Roles.moderator)
assert isinstance(token, text_type)
diff --git a/tests/validate_jwt.py b/tests/validate_jwt.py
index 00e4aa7..592f614 100644
--- a/tests/validate_jwt.py
+++ b/tests/validate_jwt.py
@@ -5,7 +5,7 @@
def validate_jwt_header(self, jsonwebtoken):
- claims = decode(jsonwebtoken, self.api_secret, algorithms=[u("HS256")])
+ claims = decode(jsonwebtoken, self.api_secret, algorithms=["HS256", "RS256"])
expect(claims).to(have_key(u("iss")))
expect(claims[u("iss")]).to(equal(self.api_key))
expect(claims).to(have_key(u("ist")))