66require "openssl"
77require "active_support"
88require "active_support/time"
9+ require "jwt"
910
1011module OpenTok
1112 # @private
1213 module TokenGenerator
14+ VALID_TOKEN_TYPES = [ 'T1' , 'JWT' ] . freeze
15+
1316 # this works when using include TokenGenerator
1417 def self . included ( base )
1518 base . extend ( ClassMethods )
@@ -33,7 +36,14 @@ def generates_tokens(arg_lambdas={})
3336 end
3437 dynamic_args . compact!
3538 args = args . first ( 4 -dynamic_args . length )
36- self . class . generate_token . call ( *dynamic_args , *args )
39+ token_type = if args . any? && args . last . is_a? ( Hash ) && args . last . has_key? ( :token_type )
40+ args . last [ :token_type ] . upcase
41+ else
42+ "JWT"
43+ end
44+ raise "'#{ token_type } ' is not a valid token type. Must be one of: #{ VALID_TOKEN_TYPES . join ( ', ' ) } " unless VALID_TOKEN_TYPES . include? token_type
45+
46+ self . class . generate_token ( token_type ) . call ( *dynamic_args , *args )
3747 end
3848 end
3949
@@ -43,14 +53,14 @@ def arg_lambdas
4353 end
4454
4555 # Generates a token
46- def generate_token
47- TokenGenerator ::GENERATE_TOKEN_LAMBDA
56+ def generate_token ( token_type )
57+ token_type == 'T1' ? TokenGenerator ::GENERATE_T1_TOKEN_LAMBDA : TokenGenerator :: GENERATE_JWT_LAMBDA
4858 end
4959
5060 end
5161
5262 # @private TODO: this probably doesn't need to be a constant anyone can read
53- GENERATE_TOKEN_LAMBDA = -> ( api_key , api_secret , session_id , opts = { } ) do
63+ GENERATE_T1_TOKEN_LAMBDA = -> ( api_key , api_secret , session_id , opts = { } ) do
5464 # normalize required data params
5565 role = opts . fetch ( :role , :publisher )
5666 unless ROLES . has_key? role
@@ -101,6 +111,52 @@ def generate_token
101111 TOKEN_SENTINEL + Base64 . strict_encode64 ( meta_string + ":" + data_string )
102112 end
103113
114+ GENERATE_JWT_LAMBDA = -> ( api_key , api_secret , session_id , opts = { } ) do
115+ # normalize required data params
116+ role = opts . fetch ( :role , :publisher )
117+ unless ROLES . has_key? role
118+ raise "'#{ role } ' is not a recognized role"
119+ end
120+ unless Session . belongs_to_api_key? session_id . to_s , api_key
121+ raise "Cannot generate token for a session_id that doesn't belong to api_key: #{ api_key } "
122+ end
123+
124+ # minimum data params
125+ data_params = {
126+ :iss => api_key ,
127+ :ist => "project" ,
128+ :iat => Time . now . to_i ,
129+ :nonce => Random . rand ,
130+ :role => role ,
131+ :scope => "session.connect" ,
132+ :session_id => session_id ,
133+ }
134+
135+ # normalize and add additional data params
136+ unless ( expire_time = opts [ :expire_time ] . to_i ) == 0
137+ unless expire_time . between? ( Time . now . to_i , ( Time . now + 30 . days ) . to_i )
138+ raise "Expire time must be within the next 30 days"
139+ end
140+ data_params [ :exp ] = expire_time . to_i
141+ end
142+
143+ unless opts [ :data ] . nil?
144+ unless ( data = opts [ :data ] . to_s ) . length < 1000
145+ raise "Connection data must be less than 1000 characters"
146+ end
147+ data_params [ :connection_data ] = data
148+ end
149+
150+ if opts [ :initial_layout_class_list ]
151+ if opts [ :initial_layout_class_list ] . is_a? ( Array )
152+ data_params [ :initial_layout_class_list ] = opts [ :initial_layout_class_list ] . join ( ' ' )
153+ else
154+ data_params [ :initial_layout_class_list ] = opts [ :initial_layout_class_list ] . to_s
155+ end
156+ end
157+
158+ JWT . encode ( data_params , api_secret , 'HS256' , header_fields = { typ : 'JWT' } )
159+ end
104160
105161 # this works when using extend TokenGenerator
106162 # def generates_tokens(method_opts)
0 commit comments