6
6
require "openssl"
7
7
require "active_support"
8
8
require "active_support/time"
9
+ require "jwt"
9
10
10
11
module OpenTok
11
12
# @private
12
13
module TokenGenerator
14
+ VALID_TOKEN_TYPES = [ 'T1' , 'JWT' ] . freeze
15
+
13
16
# this works when using include TokenGenerator
14
17
def self . included ( base )
15
18
base . extend ( ClassMethods )
@@ -33,7 +36,14 @@ def generates_tokens(arg_lambdas={})
33
36
end
34
37
dynamic_args . compact!
35
38
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 )
37
47
end
38
48
end
39
49
@@ -43,14 +53,14 @@ def arg_lambdas
43
53
end
44
54
45
55
# 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
48
58
end
49
59
50
60
end
51
61
52
62
# @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
54
64
# normalize required data params
55
65
role = opts . fetch ( :role , :publisher )
56
66
unless ROLES . has_key? role
@@ -101,6 +111,52 @@ def generate_token
101
111
TOKEN_SENTINEL + Base64 . strict_encode64 ( meta_string + ":" + data_string )
102
112
end
103
113
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
104
160
105
161
# this works when using extend TokenGenerator
106
162
# def generates_tokens(method_opts)
0 commit comments