amazon-chime-sdk-rails 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6a4ee22a82debfa8f285e8516c9b6f80bc82be4cd26ed45dd65d7ea2e05170f8
4
- data.tar.gz: fcf6109a79b1ca6535b10fbcf51994708a80409601daade46b2fa10cfd9a22e0
3
+ metadata.gz: 168cdb6149788c0f8499ae2499df0f0d2a5590dacccaf0eed854704e91f7d3e6
4
+ data.tar.gz: a7d0c20d4a39929afe2b60b0c0b01f74181ab0807c5c27d76f2cc98a5a1760fe
5
5
  SHA512:
6
- metadata.gz: 3a153f6055287f2eb6d20e44012afb50ed0a6554be21d2563dc1a0955f943cf053e1d64b73ac086721dec83b9bdda3473dfeef51b5d817f1f347548b90c7c1c9
7
- data.tar.gz: 99466f46ccd52dcce9c71dcaca1422b96af51ff68023bc41b529f3401a09c8b5368e0db93df2c05dd5ad25d8b9b87d67d19469a113017bbdc2d054b238a92942
6
+ metadata.gz: e1be855d627474e0382b628578a70457beeff4b2f0f3400d107f35d99dc7e8a31020163137fc6e186eb4ff67754b17b957a16d809e0f6c751ecb563e198167d0
7
+ data.tar.gz: 2ce6405a5317f87052777b3830c844e6e5dd5702c2fa14ce1ff425ab04de70f6c69778d624d0268dec08d356ab801f148c7c64471ae4c04d39028780769f0141
@@ -0,0 +1,7 @@
1
+ version: 2
2
+ updates:
3
+ # Actions are pinned to commit SHAs; this keeps the pins current.
4
+ - package-ecosystem: github-actions
5
+ directory: /
6
+ schedule:
7
+ interval: weekly
@@ -15,6 +15,9 @@ env:
15
15
  # https://nodejs.org/en/about/previous-releases
16
16
  node-version: 24.x
17
17
 
18
+ permissions:
19
+ contents: read
20
+
18
21
  jobs:
19
22
  build:
20
23
  runs-on: ubuntu-latest
@@ -48,14 +51,14 @@ jobs:
48
51
  BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile }}
49
52
 
50
53
  steps:
51
- - uses: actions/checkout@v5
54
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
52
55
  - name: Set up Ruby
53
- uses: ruby/setup-ruby@v1
56
+ uses: ruby/setup-ruby@7f797815d8adceb1c412e7abefdd1ab4abc47a5f # v1.335.0
54
57
  with:
55
58
  ruby-version: ${{ matrix.ruby-version }}
56
59
  bundler-cache: true
57
60
  - name: Set up Node.js
58
- uses: actions/setup-node@v5
61
+ uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
59
62
  with:
60
63
  node-version: ${{ env.node-version }}
61
64
  - name: Prepare test application
data/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ ## 2.2.0 / 2026-10-28
2
+ [Full Changelog](http://github.com/simukappu/amazon-chime-sdk-rails/compare/v2.1.0...v2.2.0)
3
+
4
+ Security Fixes:
5
+
6
+ * Verify that requested meetings belong to the requesting resource. Meetings and attendees controllers now respond with 404 when the meeting's `ExternalMeetingId` is not `config.prefix + meeting_request_id`, so users can no longer get, delete, or join meetings of other resources (such as other private rooms) by meeting ID
7
+ * Attendees controllers must now define `meeting_request_id` with the same value as the meetings controller. The generated attendees controller template includes it
8
+ * Set `config.verify_meeting_request_id = false`, or override `verify_meeting_request_id?` in a controller, to restore the previous behavior
9
+ * Do not return `JoinToken` from attendees `index` and `show` actions. A join token is the credential to join a meeting as that attendee, so other participants could impersonate the attendee
10
+ * Do not create meetings or attendees by HTTP GET request parameters. `create_meeting` in meetings `index` and `create_attendee_from_meeting` in meetings `show` can now only disable the creation enabled by `config.create_meeting_by_get_request` and `config.create_attendee_from_meeting`, since GET requests are not protected from CSRF
11
+ * Raise `NotImplementedError` from `attendee_request_id` unless it is defined in your controllers. The previous default `"default"` made every user join meetings as the same attendee with the same join token. The generated controller templates also raise it until you define `attendee_request_id`
12
+ * Build the attendee list in the generated meeting view with `textContent` instead of `innerHTML`, so attendee names from application metadata cannot inject HTML
13
+ * Remove the unpinned axios script loaded from unpkg in the generated meeting view and use `fetch` instead
14
+ * Pin the aws-samples/amazon-chime-sdk commit that `rails g chime_sdk:js` clones and runs npm scripts in
15
+
1
16
  ## 2.1.0 / 2026-04-11
2
17
  [Full Changelog](http://github.com/simukappu/amazon-chime-sdk-rails/compare/v2.0.1...v2.1.0)
3
18
 
data/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # amazon-chime-sdk-rails
2
2
 
3
- [![Build Status](https://github.com/simukappu/amazon-chime-sdk-rails/actions/workflows/build.yml/badge.svg)](https://github.com/simukappu/amazon-chime-sdk-rails/actions/workflows/build.yml)
4
- [![Coverage Status](https://coveralls.io/repos/github/simukappu/amazon-chime-sdk-rails/badge.svg?branch=master)](https://coveralls.io/github/simukappu/amazon-chime-sdk-rails?branch=master)
5
3
  [![Gem Version](https://badge.fury.io/rb/amazon-chime-sdk-rails.svg)](https://rubygems.org/gems/amazon-chime-sdk-rails)
6
4
  [![Gem Downloads](https://img.shields.io/gem/dt/amazon-chime-sdk-rails.svg)](https://rubygems.org/gems/amazon-chime-sdk-rails)
7
- [![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](LICENSE)
5
+ [![Build Status](https://github.com/simukappu/amazon-chime-sdk-rails/actions/workflows/build.yml/badge.svg)](https://github.com/simukappu/amazon-chime-sdk-rails/actions/workflows/build.yml)
6
+ [![Coverage Status](https://coveralls.io/repos/github/simukappu/amazon-chime-sdk-rails/badge.svg?branch=master)](https://coveralls.io/github/simukappu/amazon-chime-sdk-rails?branch=master)
7
+ [![License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](LICENSE)
8
8
 
9
9
  *amazon-chime-sdk-rails* brings server-side implementation of [Amazon Chime SDK](https://aws.amazon.com/chime/chime-sdk) to your [Ruby on Rails](https://rubyonrails.org) application. [Amazon Chime SDK](https://aws.amazon.com/chime/chime-sdk) provides client-side implementation to build real-time communications for your application, and *amazon-chime-sdk-rails* enables you to easily add server-side implementation to your Rails application.
10
10
 
@@ -185,7 +185,7 @@ class Api::MeetingsController < ApplicationController
185
185
  "PrivateRoom-#{@room.id}"
186
186
  end
187
187
 
188
- # Uncomment and update
188
+ # Update (replace raise NotImplementedError)
189
189
  def attendee_request_id
190
190
  "User-#{current_api_user.id}"
191
191
  end
@@ -234,7 +234,12 @@ class Api::MeetingAttendeesController < ApplicationController
234
234
  end
235
235
  end
236
236
 
237
- # Uncomment and update
237
+ # Uncomment (use the same value as your meetings controller)
238
+ def meeting_request_id
239
+ "PrivateRoom-#{@room.id}"
240
+ end
241
+
242
+ # Update (replace raise NotImplementedError)
238
243
  def attendee_request_id
239
244
  "User-#{current_api_user.id}"
240
245
  end
@@ -251,7 +251,7 @@ class MeetingsController < ApplicationController
251
251
  "PrivateRoom-#{@room.id}"
252
252
  end
253
253
 
254
- # Uncomment
254
+ # Update (replace raise NotImplementedError)
255
255
  def attendee_request_id
256
256
  "User-#{current_user.id}"
257
257
  end
@@ -299,7 +299,12 @@ class MeetingAttendeesController < ApplicationController
299
299
  end
300
300
  end
301
301
 
302
- # Uncomment
302
+ # Uncomment (use the same value as your meetings controller)
303
+ def meeting_request_id
304
+ "PrivateRoom-#{@room.id}"
305
+ end
306
+
307
+ # Update (replace raise NotImplementedError)
303
308
  def attendee_request_id
304
309
  "User-#{current_user.id}"
305
310
  end
@@ -64,6 +64,15 @@ module ChimeSdk
64
64
  # @return [Boolean] Whether the application creates meeting in meetings#index action by HTTP GET request
65
65
  attr_accessor :create_meeting_by_get_request
66
66
 
67
+ # @overload verify_meeting_request_id
68
+ # Return whether the controllers verify that requested meetings were created with ChimeSdk.config.prefix + meeting_request_id.
69
+ # @return [Boolean] Whether the controllers verify that requested meetings were created with ChimeSdk.config.prefix + meeting_request_id
70
+ # @overload verify_meeting_request_id=(value)
71
+ # Set whether the controllers verify that requested meetings were created with ChimeSdk.config.prefix + meeting_request_id.
72
+ # @param [Boolean] verify_meeting_request_id The new verify_meeting_request_id
73
+ # @return [Boolean] Whether the controllers verify that requested meetings were created with ChimeSdk.config.prefix + meeting_request_id
74
+ attr_accessor :verify_meeting_request_id
75
+
67
76
  # Initialize configuration for ChimeSdk.
68
77
  # These configuration can be overridden in initializer.
69
78
  # @return [Config] A new instance of Config
@@ -75,6 +84,7 @@ module ChimeSdk
75
84
  @create_meeting_with_attendee = true
76
85
  @create_attendee_from_meeting = true
77
86
  @create_meeting_by_get_request = false
87
+ @verify_meeting_request_id = true
78
88
  end
79
89
  end
80
90
  end
@@ -12,15 +12,17 @@ module ChimeSdk
12
12
  end
13
13
 
14
14
  # GET /meetings/:meeting_id/attendees
15
+ # Join tokens are omitted since they are credentials of each attendee.
15
16
  def index
16
17
  list_attendees
17
- render json: { attendees: @attendees }
18
+ render json: { attendees: @attendees.map { |attendee| without_join_token(attendee) } }
18
19
  end
19
20
 
20
21
  # GET /meetings/:meeting_id/attendees/:attendee_id
22
+ # The join token is omitted since it is a credential of the attendee.
21
23
  def show
22
24
  get_attendee
23
- render json: @attendee
25
+ render json: without_join_token(@attendee)
24
26
  end
25
27
 
26
28
  # POST /meetings/:meeting_id/attendees
@@ -55,13 +57,25 @@ module ChimeSdk
55
57
  params[:id]
56
58
  end
57
59
 
60
+ # Unique meeting request id to identify meeting by Amazon Chime.
61
+ # Configure it depending on your application resources to identify meeting.
62
+ # For example, set "PrivateRoom-#{@room.id}" by Room model.
63
+ # Requested meetings are verified with this id when ChimeSdk.config.verify_meeting_request_id is enabled.
64
+ # @api protected
65
+ # @return [String] Unique meeting request id to identify meeting by Amazon Chime
66
+ def meeting_request_id
67
+ "default"
68
+ end
69
+
58
70
  # Unique attendee request id to identify attendee by Amazon Chime.
59
71
  # Configure it depending on your application resources to identify attendee.
60
72
  # For example, set "User-#{current_user.id}" by User model.
73
+ # Each user must have a different value, since users with the same value join meetings as the same attendee.
61
74
  # @api protected
62
75
  # @return [String] Unique attendee request id to identify attendee by Amazon Chime
76
+ # @raise [NotImplementedError] Unless overridden in your controllers
63
77
  def attendee_request_id
64
- "default"
78
+ raise NotImplementedError, "Define attendee_request_id in #{self.class.name} to identify each attendee, e.g. \"User-\#{current_user.id}\""
65
79
  end
66
80
 
67
81
  # Path for meetings#index action such as meetings_path.
@@ -1,6 +1,9 @@
1
1
  module ChimeSdk
2
2
  # Controllers implementation by amazon-chime-sdk-rails.
3
3
  module Controller
4
+ # Error raised when the requested meeting is not the meeting identified by meeting_request_id.
5
+ class MeetingNotFoundError < StandardError; end
6
+
4
7
  # Common implementation for controllers.
5
8
  module Common
6
9
  extend ActiveSupport::Concern
@@ -9,6 +12,7 @@ module ChimeSdk
9
12
  rescue_from Aws::ChimeSDKMeetings::Errors::ForbiddenException, with: :render_forbidden
10
13
  rescue_from Aws::ChimeSDKMeetings::Errors::NotFoundException, with: :render_resource_not_found
11
14
  rescue_from Aws::ChimeSDKMeetings::Errors::ValidationException, with: :render_resource_not_found
15
+ rescue_from ChimeSdk::Controller::MeetingNotFoundError, with: :render_resource_not_found
12
16
 
13
17
  class ::String
14
18
  # Convets to boolean.
@@ -51,7 +55,7 @@ module ChimeSdk
51
55
  # @api protected
52
56
  # @return [Hash] Meeting
53
57
  def get_meeting
54
- @meeting = ChimeSdk::MeetingCoordinator.get_meeting(meeting_id)
58
+ @meeting = verify_meeting(ChimeSdk::MeetingCoordinator.get_meeting(meeting_id))
55
59
  @meeting = merge_application_meeting_metadata(@meeting)
56
60
  end
57
61
 
@@ -59,13 +63,43 @@ module ChimeSdk
59
63
  # @api protected
60
64
  # @return [void]
61
65
  def delete_meeting
66
+ verify_meeting_id
62
67
  ChimeSdk::MeetingCoordinator.delete_meeting(meeting_id)
63
68
  end
64
69
 
70
+ # Whether to verify that requested meetings were created with ChimeSdk.config.prefix + meeting_request_id.
71
+ # Override it to change the behavior for each controller.
72
+ # @api protected
73
+ # @return [Boolean] Whether to verify requested meetings
74
+ def verify_meeting_request_id?
75
+ ChimeSdk.config.verify_meeting_request_id
76
+ end
77
+
78
+ # Verify that the meeting was created with ChimeSdk.config.prefix + meeting_request_id.
79
+ # @api protected
80
+ # @param [Hash] meeting Meeting JSON object as hash
81
+ # @return [Hash] Verified meeting
82
+ # @raise [ChimeSdk::Controller::MeetingNotFoundError] When the meeting is not the meeting identified by meeting_request_id
83
+ def verify_meeting(meeting)
84
+ if verify_meeting_request_id? && meeting.dig(:Meeting, :ExternalMeetingId) != ChimeSdk.config.prefix + meeting_request_id
85
+ raise ChimeSdk::Controller::MeetingNotFoundError, "Meeting not found"
86
+ end
87
+ meeting
88
+ end
89
+
90
+ # Verify the requested meeting by meeting id unless it has already been verified.
91
+ # @api protected
92
+ # @return [void]
93
+ # @raise [ChimeSdk::Controller::MeetingNotFoundError] When the meeting is not the meeting identified by meeting_request_id
94
+ def verify_meeting_id
95
+ verify_meeting(ChimeSdk::MeetingCoordinator.get_meeting(meeting_id)) if @meeting.nil? && verify_meeting_request_id?
96
+ end
97
+
65
98
  # List attendees by MeetingCoordinator.
66
99
  # @api protected
67
100
  # @return [Array<Hash>] Attendee list
68
101
  def list_attendees
102
+ verify_meeting_id
69
103
  @attendees = ChimeSdk::MeetingCoordinator.list_attendees(meeting_id)
70
104
  @attendees = @attendees.map { |attendee| merge_application_attendee_metadata(attendee) }
71
105
  end
@@ -74,6 +108,7 @@ module ChimeSdk
74
108
  # @api protected
75
109
  # @return [Hash] Created attendee
76
110
  def create_attendee
111
+ verify_meeting_id
77
112
  @attendee = ChimeSdk::MeetingCoordinator.create_attendee(meeting_id, attendee_request_id)
78
113
  @attendee = merge_application_attendee_metadata(@attendee)
79
114
  end
@@ -82,6 +117,7 @@ module ChimeSdk
82
117
  # @api protected
83
118
  # @return [Hash] Attendee
84
119
  def get_attendee
120
+ verify_meeting_id
85
121
  @attendee = ChimeSdk::MeetingCoordinator.get_attendee(meeting_id, attendee_id)
86
122
  @attendee = merge_application_attendee_metadata(@attendee)
87
123
  end
@@ -90,6 +126,7 @@ module ChimeSdk
90
126
  # @api protected
91
127
  # @return [void]
92
128
  def delete_attendee
129
+ verify_meeting_id
93
130
  ChimeSdk::MeetingCoordinator.delete_attendee(meeting_id, attendee_id)
94
131
  end
95
132
 
@@ -154,6 +191,15 @@ module ChimeSdk
154
191
  attendee
155
192
  end
156
193
 
194
+ # Return attendee without its join token.
195
+ # Join token is a credential to join the meeting as the attendee and must not be returned to other users.
196
+ # @api protected
197
+ # @param [Hash] attendee Attendee JSON object as hash
198
+ # @return [Hash] Attendee without join token
199
+ def without_join_token(attendee)
200
+ attendee.merge(Attendee: attendee[:Attendee].except(:JoinToken))
201
+ end
202
+
157
203
  # Returns error response as Hash
158
204
  # @api protected
159
205
  # @return [Hash] Error message
@@ -16,9 +16,9 @@ module ChimeSdk
16
16
  # GET /meetings.json
17
17
  # @overload index(params)
18
18
  # @param [Hash] params Request parameter options
19
- # @option params [String] :create_meeting (ChimeSdk.config.create_meeting_by_get_request) Whether the application creates meeting in this meetings#index action by HTTP GET request
19
+ # @option params [String] :create_meeting (ChimeSdk.config.create_meeting_by_get_request) Whether the application creates meeting in this meetings#index action by HTTP GET request. This parameter can only disable it since GET requests are not protected from CSRF.
20
20
  def index
21
- if params[:create_meeting].to_s.to_boolean(false) || ChimeSdk.config.create_meeting_by_get_request && params[:create_meeting].to_s.to_boolean(true)
21
+ if ChimeSdk.config.create_meeting_by_get_request && params[:create_meeting].to_s.to_boolean(true)
22
22
  create
23
23
  else
24
24
  @meeting_request_id = ChimeSdk.config.prefix + meeting_request_id
@@ -34,10 +34,10 @@ module ChimeSdk
34
34
  # GET /meetings/:meeting_id.json
35
35
  # @overload show(params)
36
36
  # @param [Hash] params Request parameter options
37
- # @option params [String] :create_attendee_from_meeting (ChimeSdk.config.create_attendee_from_meeting) Whether the application creates attendee from meeting in meetings#show action
37
+ # @option params [String] :create_attendee_from_meeting (ChimeSdk.config.create_attendee_from_meeting) Whether the application creates attendee from meeting in meetings#show action. This parameter can only disable it since GET requests are not protected from CSRF.
38
38
  def show
39
39
  get_meeting
40
- if params[:create_attendee_from_meeting].to_s.to_boolean(false) || ChimeSdk.config.create_attendee_from_meeting && params[:create_attendee_from_meeting].to_s.to_boolean(true)
40
+ if ChimeSdk.config.create_attendee_from_meeting && params[:create_attendee_from_meeting].to_s.to_boolean(true)
41
41
  create_attendee_from_meeting
42
42
  end
43
43
  respond_to do |format|
@@ -97,10 +97,12 @@ module ChimeSdk
97
97
  # Unique attendee request id to identify attendee by Amazon Chime.
98
98
  # Configure it depending on your application resources to identify attendee.
99
99
  # For example, set "User-#{current_user.id}" by User model.
100
+ # Each user must have a different value, since users with the same value join meetings as the same attendee.
100
101
  # @api protected
101
102
  # @return [String] Unique attendee request id to identify attendee by Amazon Chime
103
+ # @raise [NotImplementedError] Unless overridden in your controllers
102
104
  def attendee_request_id
103
- "default"
105
+ raise NotImplementedError, "Define attendee_request_id in #{self.class.name} to identify each attendee, e.g. \"User-\#{current_user.id}\""
104
106
  end
105
107
 
106
108
  # Path for meetings#index action such as meetings_path.
@@ -1,4 +1,4 @@
1
1
  module ChimeSdk
2
2
  # Gem version of amazon-chime-sdk-rails
3
- VERSION = "2.1.0"
3
+ VERSION = "2.2.0"
4
4
  end
@@ -4,13 +4,17 @@ module ChimeSdk
4
4
  module Generators
5
5
  # Amazon Chime SDK single .js file generator.
6
6
  # Bundle Amazon Chime SDK into single amazon-chime-sdk.min.js file and copy it to app/assets/javascripts directory.
7
- # @example Run Amazon Chime SDK single .js file generator with the latest version from master branch
7
+ # @example Run Amazon Chime SDK single .js file generator with the version in the pinned singlejs package.json
8
8
  # rails generate chime_sdk:js
9
9
  # @example Run Amazon Chime SDK single .js file generator with specified version
10
10
  # rails generate chime_sdk:js 2.24.0
11
11
  # @see https://github.com/aws-samples/amazon-chime-sdk/tree/main/utils/singlejs
12
12
  # @see https://www.npmjs.com/package/amazon-chime-sdk-js
13
13
  class JsGenerator < Rails::Generators::Base
14
+ # Commit of aws-samples/amazon-chime-sdk repository to build the single .js file from.
15
+ # Pinned since the generator runs npm scripts in the cloned repository.
16
+ SINGLEJS_REPOSITORY_COMMIT = "6abe76a732c1fce4cce9d2dbbf28946482ac203e"
17
+
14
18
  desc <<-DESC.strip_heredoc
15
19
  Bundle Amazon Chime SDK into single amazon-chime-sdk.min.js file and copy it to app/assets/javascripts directory.
16
20
 
@@ -76,6 +80,7 @@ module ChimeSdk
76
80
  system "mkdir -p tmp"
77
81
  puts "Cloning into 'amazon-chime-sdk-js' git repository in tmp directory ..."
78
82
  system "cd tmp; git clone https://github.com/aws-samples/amazon-chime-sdk.git > /dev/null 2>&1"
83
+ system "cd tmp/amazon-chime-sdk; git -c advice.detachedHead=false checkout #{SINGLEJS_REPOSITORY_COMMIT} > /dev/null 2>&1"
79
84
  repository_path = "tmp/amazon-chime-sdk"
80
85
  singlejs_path = "#{repository_path}/utils/singlejs"
81
86
  package_json_path = "#{singlejs_path}/package.json"
@@ -22,4 +22,9 @@ ChimeSdk.configure do |config|
22
22
 
23
23
  # Configure whether the application creates meeting in meetings#index action by HTTP GET request.
24
24
  config.create_meeting_by_get_request = false
25
+
26
+ # Configure whether the controllers verify that requested meetings were created with config.prefix + meeting_request_id.
27
+ # When enabled, meetings and attendees controllers respond with 404 for meetings of other resources, such as other private rooms.
28
+ # Default value is true. Disabling it allows any meeting in your AWS account to be accessed by its meeting id.
29
+ config.verify_meeting_request_id = true
25
30
  end
@@ -23,14 +23,26 @@ class <%= @namespace %><%= @class_name_prefix %>MeetingAttendeesController < App
23
23
  # params[:id]
24
24
  # end
25
25
 
26
+ # Unique meeting request id to identify meeting by Amazon Chime.
27
+ # Configure it depending on your application resources to identify meeting.
28
+ # For example, set "PrivateRoom-#{@room.id}" by Room model.
29
+ # Use the same value as your meetings controller since requested meetings are verified with this id.
30
+ # @api protected
31
+ # @return [String] Unique meeting request id to identify meeting by Amazon Chime
32
+ def meeting_request_id
33
+ # "PrivateRoom-#{@room.id}"
34
+ "<%= @default_meeting_request_id %>"
35
+ end
36
+
26
37
  # Unique attendee request id to identify attendee by Amazon Chime.
27
38
  # Configure it depending on your application resources to identify attendee.
28
39
  # For example, set "User-#{current_user.id}" by User model.
40
+ # Each user must have a different value, since users with the same value join meetings as the same attendee.
29
41
  # @api protected
30
42
  # @return [String] Unique attendee request id to identify attendee by Amazon Chime
31
43
  def attendee_request_id
32
44
  # "User-#{current_user.id}"
33
- "default"
45
+ raise NotImplementedError, "Define attendee_request_id in #{self.class.name} to identify each attendee, e.g. \"User-\#{current_user.id}\""
34
46
  end
35
47
 
36
48
  # Path for meetings#index action such as meetings_path.
@@ -28,11 +28,12 @@ class <%= @namespace %><%= @class_name_prefix %>MeetingsController < Application
28
28
  # Unique attendee request id to identify attendee by Amazon Chime.
29
29
  # Configure it depending on your application resources to identify attendee.
30
30
  # For example, set "User-#{current_user.id}" by User model.
31
+ # Each user must have a different value, since users with the same value join meetings as the same attendee.
31
32
  # @api protected
32
33
  # @return [String] Unique attendee request id to identify attendee by Amazon Chime
33
34
  def attendee_request_id
34
35
  # "User-#{current_user.id}"
35
- "default"
36
+ raise NotImplementedError, "Define attendee_request_id in #{self.class.name} to identify each attendee, e.g. \"User-\#{current_user.id}\""
36
37
  end
37
38
 
38
39
  # Path for meetings#index action such as meetings_path.
@@ -38,7 +38,6 @@
38
38
  <% end %>
39
39
 
40
40
  <%= javascript_include_tag "amazon-chime-sdk.min.js" %>
41
- <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
42
41
 
43
42
  <script defer>
44
43
  // This is a very simple script as a template view using Amazon Chime SDK.
@@ -63,9 +62,16 @@
63
62
  const configuration = new ChimeSDK.MeetingSessionConfiguration(meeting, attendee);
64
63
  const meetingSession = new ChimeSDK.DefaultMeetingSession(configuration, logger, deviceController);
65
64
 
66
- const attendeeApi = axios.create({
67
- baseURL: `${attendeeResourcesPath}/`
68
- });
65
+ async function getAttendee(attendeeId) {
66
+ const response = await fetch(`${attendeeResourcesPath}/${encodeURIComponent(attendeeId)}`, {
67
+ headers: { 'Accept': 'application/json' },
68
+ credentials: 'same-origin'
69
+ });
70
+ if (!response.ok) {
71
+ throw new Error(`Failed to get attendee: ${response.status}`);
72
+ }
73
+ return response.json();
74
+ }
69
75
 
70
76
  async function join() {
71
77
  try {
@@ -109,9 +115,9 @@
109
115
  const presentAttendeeMap = {};
110
116
  const callback = (presentAttendeeId, present) => {
111
117
  if (present) {
112
- attendeeApi.get(presentAttendeeId)
113
- .then(response => {
114
- presentAttendeeMap[presentAttendeeId] = response.data;
118
+ getAttendee(presentAttendeeId)
119
+ .then(attendee => {
120
+ presentAttendeeMap[presentAttendeeId] = attendee;
115
121
  updateAttendeeStatus(presentAttendeeMap);
116
122
  })
117
123
  .catch(error => {
@@ -126,11 +132,15 @@
126
132
  }
127
133
 
128
134
  function updateAttendeeStatus(presentAttendeeMap) {
129
- presentAttendees = "<strong>Present Attendees</strong><ul>";
135
+ // Use textContent since attendee names are user-provided values
136
+ const title = document.createElement('strong');
137
+ title.textContent = 'Present Attendees';
138
+ const list = document.createElement('ul');
130
139
  Object.values(presentAttendeeMap).forEach(attendee => {
131
- presentAttendees = presentAttendees + `<li>${showApplicationUserName(attendee)}</li>`
140
+ const item = document.createElement('li');
141
+ item.textContent = showApplicationUserName(attendee);
142
+ list.appendChild(item);
132
143
  });
133
- presentAttendees = presentAttendees + '</ul>'
134
- document.getElementById("attendee-status").innerHTML = presentAttendees;
144
+ document.getElementById("attendee-status").replaceChildren(title, list);
135
145
  }
136
146
  </script>
@@ -29,6 +29,8 @@ describe ChimeSdk::Generators::ControllersGenerator, type: :generator do
29
29
  it { is_expected.to exist }
30
30
  it { is_expected.to contain(/class MeetingAttendeesController < ApplicationController/) }
31
31
  it { is_expected.to contain(" meetings_path(params)\n") }
32
+ it { is_expected.to contain(" def meeting_request_id\n # \"PrivateRoom-\#{@room.id}\"\n \"default\"\n") }
33
+ it { is_expected.to contain(" def attendee_request_id\n # \"User-\#{current_user.id}\"\n raise NotImplementedError") }
32
34
  end
33
35
  end
34
36
 
@@ -8,4 +8,10 @@ class Api::Public::MeetingAttendeesController < ApplicationController
8
8
  "User": User.find_by_id(user_id)
9
9
  }
10
10
  end
11
+
12
+ # This public API for the React Meeting Demo accepts any meeting in the AWS account by its meeting id.
13
+ # Do not disable this verification in your applications unless you authorize access to meetings by yourself.
14
+ def verify_meeting_request_id?
15
+ false
16
+ end
11
17
  end
@@ -12,4 +12,10 @@ class Api::Public::MeetingsController < ApplicationController
12
12
  "PrivateRoom": Room.find_by_id(room_id)
13
13
  }
14
14
  end
15
+
16
+ # This public API for the React Meeting Demo accepts any meeting in the AWS account by its meeting id.
17
+ # Do not disable this verification in your applications unless you authorize access to meetings by yourself.
18
+ def verify_meeting_request_id?
19
+ false
20
+ end
15
21
  end
@@ -39,6 +39,16 @@ class MeetingAttendeesController < ApplicationController
39
39
  # params[:id]
40
40
  # end
41
41
 
42
+ # Unique meeting request id to identify meeting by Amazon Chime.
43
+ # Configure it depending on your application resources to identify meeting.
44
+ # For example, set "PrivateRoom-#{@room.id}" by Room model.
45
+ # Use the same value as your meetings controller since requested meetings are verified with this id.
46
+ # @api protected
47
+ # @return [String] Unique meeting request id to identify meeting by Amazon Chime
48
+ def meeting_request_id
49
+ "PrivateRoom-#{@room.id}"
50
+ end
51
+
42
52
  # Unique attendee request id to identify attendee by Amazon Chime.
43
53
  # Configure it depending on your application resources to identify attendee.
44
54
  # For example, set "User-#{current_user.id}" by User model.
@@ -43,7 +43,6 @@
43
43
  <% end %>
44
44
 
45
45
  <%= javascript_include_tag "amazon-chime-sdk.min.js" %>
46
- <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
47
46
 
48
47
  <script defer>
49
48
  // This is a very simple script as a template view using Amazon Chime SDK.
@@ -75,9 +74,16 @@
75
74
  const configuration = new ChimeSDK.MeetingSessionConfiguration(meeting, attendee);
76
75
  const meetingSession = new ChimeSDK.DefaultMeetingSession(configuration, logger, deviceController);
77
76
 
78
- const attendeeApi = axios.create({
79
- baseURL: `${attendeeResourcesPath}/`
80
- });
77
+ async function getAttendee(attendeeId) {
78
+ const response = await fetch(`${attendeeResourcesPath}/${encodeURIComponent(attendeeId)}`, {
79
+ headers: { 'Accept': 'application/json' },
80
+ credentials: 'same-origin'
81
+ });
82
+ if (!response.ok) {
83
+ throw new Error(`Failed to get attendee: ${response.status}`);
84
+ }
85
+ return response.json();
86
+ }
81
87
 
82
88
  async function join() {
83
89
  try {
@@ -121,9 +127,9 @@
121
127
  const presentAttendeeMap = {};
122
128
  const callback = (presentAttendeeId, present) => {
123
129
  if (present) {
124
- attendeeApi.get(presentAttendeeId)
125
- .then(response => {
126
- presentAttendeeMap[presentAttendeeId] = response.data;
130
+ getAttendee(presentAttendeeId)
131
+ .then(attendee => {
132
+ presentAttendeeMap[presentAttendeeId] = attendee;
127
133
  updateAttendeeStatus(presentAttendeeMap);
128
134
  })
129
135
  .catch(error => {
@@ -138,11 +144,15 @@
138
144
  }
139
145
 
140
146
  function updateAttendeeStatus(presentAttendeeMap) {
141
- presentAttendees = "<strong>Present Attendees</strong><ul>";
147
+ // Use textContent since attendee names are user-provided values
148
+ const title = document.createElement('strong');
149
+ title.textContent = 'Present Attendees';
150
+ const list = document.createElement('ul');
142
151
  Object.values(presentAttendeeMap).forEach(attendee => {
143
- presentAttendees = presentAttendees + `<li>${showApplicationUserName(attendee)}</li>`
152
+ const item = document.createElement('li');
153
+ item.textContent = showApplicationUserName(attendee);
154
+ list.appendChild(item);
144
155
  });
145
- presentAttendees = presentAttendees + '</ul>'
146
- document.getElementById("attendee-status").innerHTML = presentAttendees;
156
+ document.getElementById("attendee-status").replaceChildren(title, list);
147
157
  }
148
158
  </script>
@@ -8,11 +8,7 @@
8
8
  <p>
9
9
  <strong>Private Meeting:</strong>
10
10
  <p><%= link_to 'Show Meetings Index', room_meetings_path(@room) %></p>
11
- <p>
12
- Create Meeting
13
- <%= link_to 'GET', room_meetings_path(@room, create_meeting: true) %>
14
- <%= link_to 'POST', room_meetings_path(@room), method: :post %>
15
- </p>
11
+ <p><%= link_to 'Create Meeting', room_meetings_path(@room), method: :post %></p>
16
12
  </p>
17
13
 
18
14
  <p>
@@ -4,8 +4,10 @@ describe ChimeSdk::Controller::Attendees, type: :request do
4
4
  @attendee_id = "76543210-ba98-fedc-jihg-vutsrqponmlk"
5
5
  @dummy_meeting_id = "91234567-89ab-cdef-ghij-klmnopqrstuv"
6
6
  @dummy_attendee_id = "96543210-ba98-fedc-jihg-vutsrqponmlk"
7
+ @other_meeting_id = "81234567-89ab-cdef-ghij-klmnopqrstuv"
7
8
 
8
9
  @room = create(:room)
10
+ @other_room = create(:room)
9
11
  @attendee_user = create(:user)
10
12
  @room.add_member(@attendee_user)
11
13
  test_attendee = {
@@ -29,8 +31,24 @@ describe ChimeSdk::Controller::Attendees, type: :request do
29
31
  }
30
32
  }
31
33
 
34
+ meeting_of = -> (meeting_id, room) {
35
+ {
36
+ meeting_id: meeting_id,
37
+ external_meeting_id: "ChimeSdkRailsApp-test-PrivateRoom-#{room.id}",
38
+ media_region: "us-east-1",
39
+ media_placement: { audio_host_url: "dummy" }
40
+ }
41
+ }
42
+
32
43
  # Use stubs for the AWS SDK for Ruby
33
44
  client = Aws::ChimeSDKMeetings::Client.new(stub_responses: true)
45
+ client.stub_responses(:get_meeting, -> (context) {
46
+ case context.params[:meeting_id]
47
+ when @meeting_id then { meeting: meeting_of.(@meeting_id, @room) }
48
+ when @other_meeting_id then { meeting: meeting_of.(@other_meeting_id, @other_room) }
49
+ else 'ForbiddenException'
50
+ end
51
+ })
34
52
  client.stub_responses(:list_attendees, {
35
53
  attendees: [ test_attendee, dummy_attendee ]
36
54
  })
@@ -109,6 +127,12 @@ describe ChimeSdk::Controller::Attendees, type: :request do
109
127
  it "returns valid attendee in the list" do
110
128
  expect(JSON.parse(response.body)["attendees"][0]["Attendee"]["AttendeeId"]).to eq(@attendee_id)
111
129
  end
130
+
131
+ it "does not return join tokens of attendees in the list" do
132
+ JSON.parse(response.body)["attendees"].each do |attendee|
133
+ expect(attendee["Attendee"]).not_to have_key("JoinToken")
134
+ end
135
+ end
112
136
  end
113
137
 
114
138
  describe "GET /meetings/:meeting_id/attendees/:attendee_id" do
@@ -125,6 +149,10 @@ describe ChimeSdk::Controller::Attendees, type: :request do
125
149
  expect(JSON.parse(response.body)["Attendee"]["AttendeeId"]).to eq(@attendee_id)
126
150
  end
127
151
 
152
+ it "does not return join token of the attendee" do
153
+ expect(JSON.parse(response.body)["Attendee"]).not_to have_key("JoinToken")
154
+ end
155
+
128
156
  it "returns application metadata in the attendee" do
129
157
  expect(JSON.parse(response.body)["Attendee"]["ApplicationMetadata"]["User"]["id"]).to eq(@attendee_user.id)
130
158
  end
@@ -165,6 +193,34 @@ describe ChimeSdk::Controller::Attendees, type: :request do
165
193
  end
166
194
  end
167
195
 
196
+ context "when the meeting belongs to another private room" do
197
+ let(:other_meeting_path) { "#{api_path}/meetings/#{@other_meeting_id}" }
198
+
199
+ it "returns response with 404 status to GET /meetings/:meeting_id/attendees" do
200
+ expect(ChimeSdk::MeetingCoordinator).not_to receive(:list_attendees)
201
+ get "#{other_meeting_path}/attendees", headers: @auth_headers
202
+ expect(response).to have_http_status(404)
203
+ end
204
+
205
+ it "returns response with 404 status to GET /meetings/:meeting_id/attendees/:attendee_id" do
206
+ expect(ChimeSdk::MeetingCoordinator).not_to receive(:get_attendee)
207
+ get "#{other_meeting_path}/attendees/#{@attendee_id}", headers: @auth_headers
208
+ expect(response).to have_http_status(404)
209
+ end
210
+
211
+ it "returns response with 404 status to POST /meetings/:meeting_id/attendees" do
212
+ expect(ChimeSdk::MeetingCoordinator).not_to receive(:create_attendee)
213
+ post "#{other_meeting_path}/attendees", headers: @auth_headers
214
+ expect(response).to have_http_status(404)
215
+ end
216
+
217
+ it "returns response with 404 status to DELETE /meetings/:meeting_id/attendees/:attendee_id" do
218
+ expect(ChimeSdk::MeetingCoordinator).not_to receive(:delete_attendee)
219
+ delete "#{other_meeting_path}/attendees/#{@attendee_id}", headers: @auth_headers
220
+ expect(response).to have_http_status(404)
221
+ end
222
+ end
223
+
168
224
  describe "DELETE /meetings/:meeting_id/attendees/:attendee_id" do
169
225
  context "when the attendee is found" do
170
226
  before do
@@ -3,8 +3,10 @@ describe ChimeSdk::Controller::Meetings, type: :request do
3
3
  @meeting_id = "01234567-89ab-cdef-ghij-klmnopqrstuv"
4
4
  @attendee_id = "76543210-ba98-fedc-jihg-vutsrqponmlk"
5
5
  @dummy_meeting_id = "91234567-89ab-cdef-ghij-klmnopqrstuv"
6
+ @other_meeting_id = "81234567-89ab-cdef-ghij-klmnopqrstuv"
6
7
 
7
8
  @room = create(:room)
9
+ @other_room = create(:room)
8
10
  dummy_media_placement = {
9
11
  audio_host_url: "dummy",
10
12
  audio_fallback_url: "dummy",
@@ -51,10 +53,19 @@ describe ChimeSdk::Controller::Meetings, type: :request do
51
53
  meeting_arn: "arn:aws:chime:us-east-1:000000000000:meeting/#{@meeting_id}"
52
54
  }
53
55
 
56
+ other_room_meeting = test_meeting.merge(
57
+ meeting_id: @other_meeting_id,
58
+ external_meeting_id: "ChimeSdkRailsApp-test-PrivateRoom-#{@other_room.id}"
59
+ )
60
+
54
61
  # Use stubs for the AWS SDK for Ruby
55
62
  client = Aws::ChimeSDKMeetings::Client.new(stub_responses: true)
56
63
  client.stub_responses(:get_meeting, -> (context) {
57
- context.params[:meeting_id] == @meeting_id ? { meeting: test_meeting } : 'NotFoundException'
64
+ case context.params[:meeting_id]
65
+ when @meeting_id then { meeting: test_meeting }
66
+ when @other_meeting_id then { meeting: other_room_meeting }
67
+ else 'NotFoundException'
68
+ end
58
69
  })
59
70
  client.stub_responses(:create_meeting, {
60
71
  meeting: test_meeting
@@ -131,18 +142,37 @@ describe ChimeSdk::Controller::Meetings, type: :request do
131
142
  end
132
143
  end
133
144
 
134
- context "with true as create_meeting parameter" do
145
+ context "with true as create_meeting parameter and ChimeSdk.config.create_meeting_by_get_request is disabled" do
135
146
  before do
136
147
  get "#{api_path}/meetings", headers: @auth_headers, params: { create_meeting: true }
137
148
  end
138
149
 
139
- it "returns response with 201 status" do
140
- expect(response).to have_http_status(201)
150
+ it "does not create meeting" do
151
+ expect(response).to have_http_status(200)
152
+ expect(JSON.parse(response.body)["Meeting"]).to be_nil
141
153
  end
154
+ end
142
155
 
143
- it "returns created meeting" do
156
+ context "when ChimeSdk.config.create_meeting_by_get_request is enabled" do
157
+ before do
158
+ ChimeSdk.config.create_meeting_by_get_request = true
159
+ end
160
+
161
+ after do
162
+ ChimeSdk.config.create_meeting_by_get_request = false
163
+ end
164
+
165
+ it "returns created meeting with 201 status" do
166
+ get "#{api_path}/meetings", headers: @auth_headers
167
+ expect(response).to have_http_status(201)
144
168
  expect(JSON.parse(response.body)["Meeting"]["MeetingId"]).to eq(@meeting_id)
145
169
  end
170
+
171
+ it "does not create meeting with false as create_meeting parameter" do
172
+ get "#{api_path}/meetings", headers: @auth_headers, params: { create_meeting: false }
173
+ expect(response).to have_http_status(200)
174
+ expect(JSON.parse(response.body)["Meeting"]).to be_nil
175
+ end
146
176
  end
147
177
  end
148
178
 
@@ -178,6 +208,52 @@ describe ChimeSdk::Controller::Meetings, type: :request do
178
208
  expect(response).to have_http_status(404)
179
209
  end
180
210
  end
211
+
212
+ context "with true as create_attendee_from_meeting parameter and ChimeSdk.config.create_attendee_from_meeting is disabled" do
213
+ before do
214
+ ChimeSdk.config.create_attendee_from_meeting = false
215
+ get "#{api_path}/meetings/#{@meeting_id}", params: { create_attendee_from_meeting: true }, headers: @auth_headers
216
+ end
217
+
218
+ after do
219
+ ChimeSdk.config.create_attendee_from_meeting = true
220
+ end
221
+
222
+ it "does not create attendee" do
223
+ expect(response).to have_http_status(200)
224
+ expect(JSON.parse(response.body)["Attendee"]).to be_nil
225
+ end
226
+ end
227
+
228
+ context "when the meeting belongs to another private room" do
229
+ before do
230
+ get "#{api_path}/meetings/#{@other_meeting_id}", headers: @auth_headers
231
+ end
232
+
233
+ it "returns response with 404 status" do
234
+ expect(response).to have_http_status(404)
235
+ end
236
+
237
+ it "does not return the meeting" do
238
+ expect(JSON.parse(response.body)["Meeting"]).to be_nil
239
+ end
240
+ end
241
+
242
+ context "when the meeting belongs to another private room and ChimeSdk.config.verify_meeting_request_id is disabled" do
243
+ before do
244
+ ChimeSdk.config.verify_meeting_request_id = false
245
+ get "#{api_path}/meetings/#{@other_meeting_id}", params: { create_attendee_from_meeting: false }, headers: @auth_headers
246
+ end
247
+
248
+ after do
249
+ ChimeSdk.config.verify_meeting_request_id = true
250
+ end
251
+
252
+ it "returns the meeting" do
253
+ expect(response).to have_http_status(200)
254
+ expect(JSON.parse(response.body)["Meeting"]["MeetingId"]).to eq(@other_meeting_id)
255
+ end
256
+ end
181
257
  end
182
258
 
183
259
  describe "POST /meetings" do
@@ -243,6 +319,14 @@ describe ChimeSdk::Controller::Meetings, type: :request do
243
319
  expect(response).to have_http_status(404)
244
320
  end
245
321
  end
322
+
323
+ context "when the meeting belongs to another private room" do
324
+ it "returns response with 404 status without deleting the meeting" do
325
+ expect(ChimeSdk::MeetingCoordinator).not_to receive(:delete_meeting)
326
+ delete "#{api_path}/meetings/#{@other_meeting_id}", headers: @auth_headers
327
+ expect(response).to have_http_status(404)
328
+ end
329
+ end
246
330
  end
247
331
  end
248
332
  end
@@ -310,16 +394,29 @@ describe ChimeSdk::Controller::Meetings, type: :request do
310
394
  end
311
395
  end
312
396
 
313
- context "with true as create_meeting parameter" do
397
+ context "with true as create_meeting parameter and ChimeSdk.config.create_meeting_by_get_request is disabled" do
314
398
  before do
315
399
  get "#{api_path}/meetings", params: { create_meeting: true }
316
400
  end
317
401
 
318
- it "returns response with 302 status" do
319
- expect(response).to have_http_status(302)
402
+ it "does not create meeting" do
403
+ expect(response).to have_http_status(200)
404
+ expect(response.body).to include("Meetings by Amazon Chime SDK")
405
+ end
406
+ end
407
+
408
+ context "when ChimeSdk.config.create_meeting_by_get_request is enabled" do
409
+ before do
410
+ ChimeSdk.config.create_meeting_by_get_request = true
411
+ get "#{api_path}/meetings"
412
+ end
413
+
414
+ after do
415
+ ChimeSdk.config.create_meeting_by_get_request = false
320
416
  end
321
417
 
322
418
  it "redirects to created meeting path" do
419
+ expect(response).to have_http_status(302)
323
420
  expect(response.body).to redirect_to("#{api_path}/meetings/#{@meeting_id}")
324
421
  end
325
422
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: amazon-chime-sdk-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shota Yamazaki
@@ -116,6 +116,7 @@ executables: []
116
116
  extensions: []
117
117
  extra_rdoc_files: []
118
118
  files:
119
+ - ".github/dependabot.yml"
119
120
  - ".github/workflows/build.yml"
120
121
  - ".gitignore"
121
122
  - ".rspec"