diff --git a/CHANGES.md b/CHANGES.md index 45e7b7a..10a8bf2 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,7 @@ -# Release v3.4.0 +# Release v3.5.0 +- Support for end-to-end encryption (E2EE) that can be specified by a user when creating an OpenTok session. +# Release v3.4.0 - Support for Audio Connector API via `connect_audio_to_websocket` method # Release v3.3.0 diff --git a/README.rst b/README.rst index 2bf36fa..811a70b 100644 --- a/README.rst +++ b/README.rst @@ -48,7 +48,7 @@ Import the package at the top of any file where you will use it. At the very lea Creating Sessions ~~~~~~~~~~~~~~~~~ -To create an OpenTok Session, use the ``opentok.create_session()`` method. There are three optional +To create an OpenTok Session, use the ``opentok.create_session()`` method. There are optional keyword parameters for this method: * ``location`` which can be set to a string containing an IP address. @@ -62,6 +62,10 @@ keyword parameters for this method: * ``archive_mode`` which specifies whether the session will be automatically archived (``always``) or not (``manual``). +* ``e2ee`` which is a boolean. This specifies whether to enable +`end-to-end encryption `_ +for the OpenTok session. + This method returns a ``Session`` object. Its ``session_id`` attribute is useful when saving to a persistent store (such as a database). diff --git a/opentok/opentok.py b/opentok/opentok.py index 09f62fa..d8d5e15 100644 --- a/opentok/opentok.py +++ b/opentok/opentok.py @@ -301,6 +301,7 @@ def create_session( location=None, media_mode=MediaModes.relayed, archive_mode=ArchiveModes.manual, + e2ee=False, ): """ Creates a new OpenTok session and returns the session ID, which uniquely identifies @@ -359,6 +360,9 @@ def create_session( situate the session in its global network. If you do not set a location hint, the OpenTok servers will be based on the first client connecting to the session. + :param Boolean e2ee: Whether to enable end-to-end encryption for a routed session + (see https://tokbox.com/developer/guides/end-to-end-encryption/). + :rtype: The Session object. The session_id property of the object is the session ID. """ @@ -395,6 +399,7 @@ def create_session( ).format(location) ) options[u("location")] = location + options["e2ee"] = e2ee try: logger.debug( @@ -436,13 +441,14 @@ def create_session( session_id = ( dom.getElementsByTagName("session_id")[0].childNodes[0].nodeValue - ) + ) return Session( self, session_id, location=location, media_mode=media_mode, archive_mode=archive_mode, + e2ee=e2ee, ) except Exception as e: raise OpenTokException("Failed to generate session: %s" % str(e)) diff --git a/opentok/version.py b/opentok/version.py index 44d145a..5f50eb0 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.4.0" +__version__ = "3.5.0" diff --git a/tests/test_session_creation.py b/tests/test_session_creation.py index 5466249..4c48997 100644 --- a/tests/test_session_creation.py +++ b/tests/test_session_creation.py @@ -54,6 +54,7 @@ def test_create_default_session(self): ) 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_routed_session(self): @@ -87,6 +88,7 @@ def test_create_routed_session(self): ) expect(session).to(have_property(u("media_mode"), MediaModes.routed)) expect(session).to(have_property(u("location"), None)) + expect(session).to(have_property(u("e2ee"), False)) @httpretty.activate def test_failure_create_routed_session(self): @@ -138,6 +140,7 @@ def test_create_session_with_location_hint(self): ) expect(session).to(have_property(u("media_mode"), MediaModes.relayed)) expect(session).to(have_property(u("location"), u("12.34.56.78"))) + expect(session).to(have_property(u("e2ee"), False)) @httpretty.activate def test_create_routed_session_with_location_hint(self): @@ -174,6 +177,7 @@ def test_create_routed_session_with_location_hint(self): ) expect(session).to(have_property(u("media_mode"), MediaModes.routed)) expect(session).to(have_property(u("location"), u("12.34.56.78"))) + expect(session).to(have_property(u("e2ee"), False)) @httpretty.activate def test_create_manual_archive_mode_session(self): @@ -209,6 +213,7 @@ def test_create_manual_archive_mode_session(self): ) expect(session).to(have_property(u("media_mode"), MediaModes.routed)) expect(session).to(have_property(u("archive_mode"), ArchiveModes.manual)) + expect(session).to(have_property(u("e2ee"), False)) @httpretty.activate def test_create_always_archive_mode_session(self): @@ -244,6 +249,7 @@ def test_create_always_archive_mode_session(self): ) expect(session).to(have_property(u("media_mode"), MediaModes.routed)) expect(session).to(have_property(u("archive_mode"), ArchiveModes.always)) + expect(session).to(have_property(u("e2ee"), False)) @httpretty.activate def test_complains_about_always_archive_mode_and_relayed_session(self): @@ -263,5 +269,32 @@ def test_complains_about_always_archive_mode_and_relayed_session(self): archive_mode=ArchiveModes.always, ) + @httpretty.activate + def test_create_session_with_e2ee(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' + ), + status=200, + content_type=u("text/xml"), + ) + + session = self.opentok.create_session(e2ee=True) + + body = parse_qs(httpretty.last_request().body) + expect(body).to(have_key(b("e2ee"), [b'True'])) + expect(session).to(be_a(Session)) + expect(session).to( + have_property( + u("session_id"), + u( + "1_MX4xMjM0NTZ-fk1vbiBNYXIgMTcgMDA6NDE6MzEgUERUIDIwMTR-MC42ODM3ODk1MzQ0OTQyODA4fg" + ), + ) + ) + expect(session).to(have_property(u("e2ee"), True)) + # TODO: all the cases that throw exceptions # TODO: custom api_url requests