diff --git a/README.md b/README.md index ef0a16c2..739b3613 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,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..b257dd33 100644 --- a/lib/opentok/opentok.rb +++ b/lib/opentok/opentok.rb @@ -144,11 +144,16 @@ 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 [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, :e2ee ] opts = opts.inject({}) do |m,(k,v)| if valid_opts.include? k.to_sym m[k.to_sym] = v @@ -159,6 +164,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 @@ -177,8 +189,6 @@ def create_session(opts={}) raise "archive mode must be either always or manual" unless ARCHIVE_MODES.include? params[:archive_mode].to_sym 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..82e84fa1 100644 --- a/lib/opentok/session.rb +++ b/lib/opentok/session.rb @@ -57,7 +57,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, :e2ee, :api_key, :api_secret # @private # this implementation doesn't completely understand the format of a Session ID @@ -73,7 +73,7 @@ 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, @location, @archive_mode, @e2ee = opts.fetch(:media_mode, :relayed), opts[:location], opts.fetch(:archive_mode, :manual), opts.fetch(:e2ee, :false) end # @private 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..934626d3 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,41 @@ 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 } + # 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 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