diff --git a/CHANGES.md b/CHANGES.md
index c984f5a0..fef6abd9 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,3 +1,9 @@
+# 4.7.0
+
+* Adds support for the End-to-end encryption (E2EE) feature [#259](https://github.com/opentok/OpenTok-Ruby-SDK/pull/259)
+* Implements Auto-archive improvements [#262](https://github.com/opentok/OpenTok-Ruby-SDK/pull/262)
+* Updates the README to explain appending a custom value to the `UserAgent` header [#263](https://github.com/opentok/OpenTok-Ruby-SDK/pull/263)
+
# 4.6.0
* Adds functionality for working with the Audio Connector feature [#247](https://github.com/opentok/OpenTok-Ruby-SDK/pull/247)
diff --git a/README.md b/README.md
index ef0a16c2..d85706e7 100644
--- a/README.md
+++ b/README.md
@@ -59,6 +59,8 @@ opentok = OpenTok::OpenTok.new api_key, api_secret
#### Initialization Options
+**Custom Timeout**
+
You can specify a custom timeout value for HTTP requests when initializing a new `OpenTok::OpenTok`
object:
@@ -71,6 +73,23 @@ opentok = OpenTok::OpenTok.new api_key, api_secret, :timeout_length => 10
The value for `:timeout_length` is an integer representing the number of seconds to wait for an HTTP
request to complete. The default is set to 2 seconds.
+**UA Addendum**
+
+You can also append a custom string to the `User-Agent` header value for HTTP requests when initializing a new `OpenTok::OpenTok`
+object:
+
+```ruby
+require "opentok"
+
+opentok = OpenTok::OpenTok.new api_key, api_secret, :ua_addendum => 'FOO'
+```
+
+The above would generate a `User-Agent` header something like this:
+
+```
+User-Agent: OpenTok-Ruby-SDK/4.6.0-Ruby-Version-3.1.2-p20 FOO
+```
+
### Creating Sessions
To create an OpenTok Session, use the `OpenTok#create_session(properties)` method.
@@ -101,6 +120,9 @@ session = opentok.create_session :location => '12.34.56.78'
# A session with automatic archiving (must use the routed media mode):
session = opentok.create_session :archive_mode => :always, :media_mode => :routed
+# A session with end-to-end encryption (must use the routed media mode):
+session = opentok.create_session :e2ee => true, :media_mode => :routed
+
# Store this sessionId in the database for later use:
session_id = session.session_id
```
diff --git a/lib/opentok/opentok.rb b/lib/opentok/opentok.rb
index 2a7e58a0..b7ecfad8 100644
--- a/lib/opentok/opentok.rb
+++ b/lib/opentok/opentok.rb
@@ -144,11 +144,26 @@ def initialize(api_key, api_secret, opts={})
# automatically (:always
) or not (:manual
). When using automatic
# archiving, the session must use the :routed
media mode.
#
+ # @option opts [Symbol] :archive_name The name to use for archives in auto-archived sessions.
+ # When setting this option, the :archive_mode option must be set to :always or an error will result.
+ # The length of the archive name can be up to 80 chars.
+ # Due to encoding limitations the following special characters are translated to a colon (:) character: ~, -, _.
+ # If you do not set a name and the archiveMode option is set to always, the archive name will be empty.
+ #
+ # @option opts [Symbol] :archive_resolution The resolution of archives in an auto-archived session.
+ # Valid values are "480x640", "640x480" (the default), "720x1280", "1280x720", "1080x1920", and "1920x1080".
+ # When setting this option, the :archive_mode option must be set to :always or an error will result.
+ #
+ # @option opts [true, false] :e2ee
+ # (Boolean, optional) — Whether the session uses end-to-end encryption from client to client (default: false).
+ # This should not be set to `true` if `:media_mode` is `:relayed`.
+ # See the {https://tokbox.com/developer/guides/end-to-end-encryption/ documentation} for more information.
+ #
# @return [Session] The Session object. The session_id property of the object is the session ID.
def create_session(opts={})
# normalize opts so all keys are symbols and only include valid_opts
- valid_opts = [ :media_mode, :location, :archive_mode ]
+ valid_opts = [ :media_mode, :location, :archive_mode, :archive_name, :archive_resolution, :e2ee ]
opts = opts.inject({}) do |m,(k,v)|
if valid_opts.include? k.to_sym
m[k.to_sym] = v
@@ -159,6 +174,13 @@ def create_session(opts={})
# keep opts around for Session constructor, build REST params
params = opts.clone
+ # validate input combinations
+ raise ArgumentError, "A session with always archive mode must also have the routed media mode." if (params[:archive_mode] == :always && params[:media_mode] == :relayed)
+
+ raise ArgumentError, "A session with relayed media mode should not have e2ee set to true." if (params[:media_mode] == :relayed && params[:e2ee] == true)
+
+ raise ArgumentError, "A session with always archive mode must not have e2ee set to true." if (params[:archive_mode] == :always && params[:e2ee] == true)
+
# anything other than :relayed sets the REST param to "disabled", in which case we force
# opts to be :routed. if we were more strict we could raise an error when the value isn't
# either :relayed or :routed
@@ -175,10 +197,9 @@ def create_session(opts={})
# archive mode is optional, but it has to be one of the valid values if present
unless params[:archive_mode].nil?
raise "archive mode must be either always or manual" unless ARCHIVE_MODES.include? params[:archive_mode].to_sym
+ raise ArgumentError, "archive name and/or archive resolution must not be set if archive mode is manual" if params[:archive_mode] == :manual && (params[:archive_name] || params[:archive_resolution])
end
- raise "A session with always archive mode must also have the routed media mode." if (params[:archive_mode] == :always && params[:media_mode] == :relayed)
-
response = client.create_session(params)
Session.new api_key, api_secret, response['sessions']['Session']['session_id'], opts
end
diff --git a/lib/opentok/session.rb b/lib/opentok/session.rb
index ccbcd0f7..4bd7fd55 100644
--- a/lib/opentok/session.rb
+++ b/lib/opentok/session.rb
@@ -20,6 +20,10 @@ module OpenTok
# @attr_reader [String] archive_mode Whether the session will be archived automatically
# (:always
) or not (:manual
).
#
+ # @attr_reader [String] archive_name The name to use for archives in auto-archived sessions.
+ #
+ # @attr_reader [String] :archive_resolution The resolution of archives in an auto-archived session.
+ #
# @!method generate_token(options)
# Generates a token.
#
@@ -57,7 +61,7 @@ class Session
:session_id => ->(instance) { instance.session_id }
})
- attr_reader :session_id, :media_mode, :location, :archive_mode, :api_key, :api_secret
+ attr_reader :session_id, :media_mode, :location, :archive_mode, :archive_name, :archive_resolution, :e2ee, :api_key, :api_secret
# @private
# this implementation doesn't completely understand the format of a Session ID
@@ -73,7 +77,12 @@ def self.belongs_to_api_key?(session_id, api_key)
# @private
def initialize(api_key, api_secret, session_id, opts={})
@api_key, @api_secret, @session_id = api_key, api_secret, session_id
- @media_mode, @location, @archive_mode = opts.fetch(:media_mode, :relayed), opts[:location], opts.fetch(:archive_mode, :manual)
+ @media_mode = opts.fetch(:media_mode, :relayed)
+ @location = opts[:location]
+ @archive_mode = opts.fetch(:archive_mode, :manual)
+ @archive_name = opts.fetch(:archive_name, '') if archive_mode == :always
+ @archive_resolution = opts.fetch(:archive_resolution, "640x480") if archive_mode == :always
+ @e2ee = opts.fetch(:e2ee, :false)
end
# @private
diff --git a/lib/opentok/version.rb b/lib/opentok/version.rb
index 70bc320c..be1ffff9 100644
--- a/lib/opentok/version.rb
+++ b/lib/opentok/version.rb
@@ -1,4 +1,4 @@
module OpenTok
# @private
- VERSION = '4.6.0'
+ VERSION = '4.7.0'
end
diff --git a/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_always_archived_sessions_with_a_set_archive_name.yml b/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_always_archived_sessions_with_a_set_archive_name.yml
new file mode 100644
index 00000000..832ae740
--- /dev/null
+++ b/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_always_archived_sessions_with_a_set_archive_name.yml
@@ -0,0 +1,42 @@
+---
+http_interactions:
+- request:
+ method: post
+ uri: https://api.opentok.com/session/create
+ body:
+ encoding: UTF-8
+ string: archiveMode=always&archiveName=foo&p2p.preference=disabled
+ headers:
+ User-Agent:
+ - OpenTok-Ruby-SDK/<%= version %>
+ X-Opentok-Auth:
+ - eyJpc3QiOiJwcm9qZWN0IiwiYWxnIjoiSFMyNTYifQ.eyJpc3MiOiIxMjM0NTYiLCJpYXQiOjE0OTI1MTA2NjAsImV4cCI6MTQ5MjUxMDk2MH0.BplMVhJWx4ld7KLKXqEmow6MjNPPFw9W8IHCMfeb120
+ Accept-Encoding:
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+ Accept:
+ - "*/*"
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Server:
+ - nginx
+ Date:
+ - Mon, 12 Jun 2023 16:17:36 GMT
+ Content-Type:
+ - text/xml
+ Connection:
+ - keep-alive
+ Access-Control-Allow-Origin:
+ - '*'
+ X-Tb-Host:
+ - fms503-nyc.tokbox.com
+ Content-Length:
+ - '282'
+ body:
+ encoding: UTF-8
+ string: 1_MX4xMjM0NTZ-fk1vbiBNYXIgMTcgMDA6NDE6MzEgUERUIDIwMTR-MC42ODM3ODk1MzQ0OTQyODA4fg123456Mon
+ Jun 12 16:17:36 GMT 2023
+ recorded_at: Tue, 18 Apr 2017 10:17:40 GMT
+recorded_with: VCR 6.0.0
diff --git a/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_always_archived_sessions_with_a_set_archive_name_and_resolution.yml b/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_always_archived_sessions_with_a_set_archive_name_and_resolution.yml
new file mode 100644
index 00000000..e7fd264f
--- /dev/null
+++ b/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_always_archived_sessions_with_a_set_archive_name_and_resolution.yml
@@ -0,0 +1,42 @@
+---
+http_interactions:
+- request:
+ method: post
+ uri: https://api.opentok.com/session/create
+ body:
+ encoding: UTF-8
+ string: archiveMode=always&archiveName=foo&archiveResolution=720x1280&p2p.preference=disabled
+ headers:
+ User-Agent:
+ - OpenTok-Ruby-SDK/<%= version %>
+ X-Opentok-Auth:
+ - eyJpc3QiOiJwcm9qZWN0IiwiYWxnIjoiSFMyNTYifQ.eyJpc3MiOiIxMjM0NTYiLCJpYXQiOjE0OTI1MTA2NjAsImV4cCI6MTQ5MjUxMDk2MH0.BplMVhJWx4ld7KLKXqEmow6MjNPPFw9W8IHCMfeb120
+ Accept-Encoding:
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+ Accept:
+ - "*/*"
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Server:
+ - nginx
+ Date:
+ - Mon, 12 Jun 2023 16:17:36 GMT
+ Content-Type:
+ - text/xml
+ Connection:
+ - keep-alive
+ Access-Control-Allow-Origin:
+ - '*'
+ X-Tb-Host:
+ - fms503-nyc.tokbox.com
+ Content-Length:
+ - '282'
+ body:
+ encoding: UTF-8
+ string: 1_MX4xMjM0NTZ-fk1vbiBNYXIgMTcgMDA6NDE6MzEgUERUIDIwMTR-MC42ODM3ODk1MzQ0OTQyODA4fg123456Mon
+ Jun 12 16:17:36 GMT 2023
+ recorded_at: Tue, 18 Apr 2017 10:17:40 GMT
+recorded_with: VCR 6.0.0
diff --git a/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_always_archived_sessions_with_a_set_archive_resolution.yml b/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_always_archived_sessions_with_a_set_archive_resolution.yml
new file mode 100644
index 00000000..4b366efb
--- /dev/null
+++ b/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_always_archived_sessions_with_a_set_archive_resolution.yml
@@ -0,0 +1,42 @@
+---
+http_interactions:
+- request:
+ method: post
+ uri: https://api.opentok.com/session/create
+ body:
+ encoding: UTF-8
+ string: archiveMode=always&archiveResolution=720x1280&p2p.preference=disabled
+ headers:
+ User-Agent:
+ - OpenTok-Ruby-SDK/<%= version %>
+ X-Opentok-Auth:
+ - eyJpc3QiOiJwcm9qZWN0IiwiYWxnIjoiSFMyNTYifQ.eyJpc3MiOiIxMjM0NTYiLCJpYXQiOjE0OTI1MTA2NjAsImV4cCI6MTQ5MjUxMDk2MH0.BplMVhJWx4ld7KLKXqEmow6MjNPPFw9W8IHCMfeb120
+ Accept-Encoding:
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+ Accept:
+ - "*/*"
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Server:
+ - nginx
+ Date:
+ - Mon, 12 Jun 2023 16:17:36 GMT
+ Content-Type:
+ - text/xml
+ Connection:
+ - keep-alive
+ Access-Control-Allow-Origin:
+ - '*'
+ X-Tb-Host:
+ - fms503-nyc.tokbox.com
+ Content-Length:
+ - '282'
+ body:
+ encoding: UTF-8
+ string: 1_MX4xMjM0NTZ-fk1vbiBNYXIgMTcgMDA6NDE6MzEgUERUIDIwMTR-MC42ODM3ODk1MzQ0OTQyODA4fg123456Mon
+ Jun 12 16:17:36 GMT 2023
+ recorded_at: Tue, 18 Apr 2017 10:17:40 GMT
+recorded_with: VCR 6.0.0
diff --git a/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_e2ee_sessions.yml b/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_e2ee_sessions.yml
new file mode 100644
index 00000000..3bcd7c20
--- /dev/null
+++ b/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_e2ee_sessions.yml
@@ -0,0 +1,40 @@
+---
+http_interactions:
+- request:
+ method: post
+ uri: https://api.opentok.com/session/create
+ body:
+ encoding: UTF-8
+ string: e2ee=true&p2p.preference=disabled
+ headers:
+ User-Agent:
+ - OpenTok-Ruby-SDK/<%= version %>
+ X-Opentok-Auth:
+ - eyJpc3QiOiJwcm9qZWN0IiwiYWxnIjoiSFMyNTYifQ.eyJpc3MiOiIxMjM0NTYiLCJpYXQiOjE0OTI1MTA2NjAsImV4cCI6MTQ5MjUxMDk2MH0.BplMVhJWx4ld7KLKXqEmow6MjNPPFw9W8IHCMfeb120
+ Accept-Encoding: "gzip;q=1.0,deflate;q=0.6,identity;q=0.3"
+ Accept: "*/*"
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Server:
+ - nginx
+ Date:
+ - Tue, 18 Apr 2023 16:17:40 GMT
+ Content-Type:
+ - text/xml
+ Connection:
+ - keep-alive
+ Access-Control-Allow-Origin:
+ - '*'
+ X-Tb-Host:
+ - mantis503-nyc.tokbox.com
+ Content-Length:
+ - '304'
+ body:
+ encoding: UTF-8
+ string: 1_MX4xMjM0NTZ-MTIuMzQuNTYuNzh-TW9uIE1hciAxNyAwMTo0ODo1NSBQRFQgMjAxNH4wLjM0MTM0MzE0MDIyOTU4Mjh-123456Tue
+ Apr 18 08:17:40 PDT 2023
+ recorded_at: Tue, 18 Apr 2023 16:17:40 GMT
+recorded_with: VCR 6.0.0
diff --git a/spec/opentok/opentok_spec.rb b/spec/opentok/opentok_spec.rb
index 11942912..7a9d3cfd 100644
--- a/spec/opentok/opentok_spec.rb
+++ b/spec/opentok/opentok_spec.rb
@@ -97,6 +97,7 @@
expect(session.media_mode).to eq :relayed
expect(session.location).to eq nil
end
+
it "creates always archived sessions", :vcr => { :erb => { :version => OpenTok::VERSION + "-Ruby-Version-#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}"} } do
session = opentok.create_session :media_mode => :routed, :archive_mode => :always
expect(session).to be_an_instance_of OpenTok::Session
@@ -105,9 +106,80 @@
expect(session.location).to eq nil
end
+ it "creates always archived sessions with a set archive name", :vcr => { :erb => { :version => OpenTok::VERSION + "-Ruby-Version-#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}"} } do
+ session = opentok.create_session :media_mode => :routed, :archive_mode => :always, :archive_name => 'foo'
+ expect(session).to be_an_instance_of OpenTok::Session
+ expect(session.session_id).to be_an_instance_of String
+ expect(session.archive_mode).to eq :always
+ expect(session.archive_name).to eq 'foo'
+ expect(session.location).to eq nil
+ end
+
+ it "creates always archived sessions with a set archive resolution", :vcr => { :erb => { :version => OpenTok::VERSION + "-Ruby-Version-#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}"} } do
+ session = opentok.create_session :media_mode => :routed, :archive_mode => :always, :archive_resolution => "720x1280"
+ expect(session).to be_an_instance_of OpenTok::Session
+ expect(session.session_id).to be_an_instance_of String
+ expect(session.archive_mode).to eq :always
+ expect(session.archive_resolution).to eq "720x1280"
+ expect(session.location).to eq nil
+ end
+
+ it "creates always archived sessions with a set archive name and resolution", :vcr => { :erb => { :version => OpenTok::VERSION + "-Ruby-Version-#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}"} } do
+ session = opentok.create_session :media_mode => :routed, :archive_mode => :always, :archive_name => 'foo', :archive_resolution => "720x1280"
+ expect(session).to be_an_instance_of OpenTok::Session
+ expect(session.session_id).to be_an_instance_of String
+ expect(session.archive_mode).to eq :always
+ expect(session.archive_name).to eq 'foo'
+ expect(session.archive_resolution).to eq "720x1280"
+ expect(session.location).to eq nil
+ end
+
+ it "creates e2ee sessions", :vcr => { :erb => { :version => OpenTok::VERSION + "-Ruby-Version-#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}"} } do
+ session = opentok.create_session :media_mode => :routed, :e2ee => :true
+ expect(session).to be_an_instance_of OpenTok::Session
+ expect(session.session_id).to be_an_instance_of String
+ expect(session.e2ee).to eq :true
+ expect(session.location).to eq nil
+ end
+
context "with relayed media mode and always archive mode" do
- subject { -> { session = opentok.create_session :archive_mode => :always, :media_mode => :relayed }}
- it { should raise_error }
+ it "raises an error" do
+ expect {
+ opentok.create_session :archive_mode => :always, :media_mode => :relayed
+ }.to raise_error ArgumentError
+ end
+ end
+
+ context "with archive name set and manual archive mode" do
+ it "raises an error" do
+ expect {
+ opentok.create_session :archive_mode => :manual, :archive_name => 'foo'
+ }.to raise_error ArgumentError
+ end
+ end
+
+ context "with archive resolution set and manual archive mode" do
+ it "raises an error" do
+ expect {
+ opentok.create_session :archive_mode => :manual, :archive_resolution => "720x1280"
+ }.to raise_error ArgumentError
+ end
+ end
+
+ context "with relayed media mode and e2ee set to true" do
+ it "raises an error" do
+ expect {
+ opentok.create_session :media_mode => :relayed, :e2ee => true
+ }.to raise_error ArgumentError
+ end
+ end
+
+ context "with always archive mode and e2ee set to true" do
+ it "raises an error" do
+ expect {
+ opentok.create_session :archive_mode => :always, :e2ee => true
+ }.to raise_error ArgumentError
+ end
end
end