|
18 | 18 |
|
19 | 19 | import com.opentok.exception.InvalidArgumentException;
|
20 | 20 | import com.opentok.util.Crypto;
|
| 21 | +import com.opentok.util.TokenGenerator; |
21 | 22 | import org.apache.commons.codec.binary.Base64;
|
| 23 | +import org.jose4j.jwt.JwtClaims; |
22 | 24 |
|
23 | 25 |
|
24 | 26 | /**
|
@@ -99,92 +101,106 @@ public String generateToken() throws OpenTokException {
|
99 | 101 | * @return The token string.
|
100 | 102 | */
|
101 | 103 | public String generateToken(TokenOptions tokenOptions) throws OpenTokException {
|
102 |
| - // Token format |
103 |
| - // |
104 |
| - // | ------------------------------ tokenStringBuilder ----------------------------- | |
105 |
| - // | "T1=="+Base64Encode(| --------------------- innerBuilder --------------------- |)| |
106 |
| - // | "partner_id={apiKey}&sig={sig}:| -- dataStringBuilder -- | |
107 | 104 |
|
108 | 105 | if (tokenOptions == null) {
|
109 | 106 | throw new InvalidArgumentException("Token options cannot be null");
|
110 | 107 | }
|
111 | 108 |
|
112 | 109 | Role role = tokenOptions.getRole();
|
113 |
| - double expireTime = tokenOptions.getExpireTime(); // will be 0 if nothing was explicitly set |
114 |
| - String data = tokenOptions.getData(); // will be null if nothing was explicitly set |
115 |
| - long create_time = System.currentTimeMillis() / 1000; |
116 |
| - |
117 |
| - StringBuilder dataStringBuilder = new StringBuilder(); |
118 |
| - Random random = new Random(); |
119 |
| - int nonce = random.nextInt(); |
120 |
| - dataStringBuilder |
121 |
| - .append("session_id=").append(sessionId) |
122 |
| - .append("&create_time=").append(create_time) |
123 |
| - .append("&nonce=").append(nonce) |
124 |
| - .append("&role=").append(role); |
125 |
| - |
126 |
| - if (tokenOptions.getInitialLayoutClassList() != null ) { |
127 |
| - dataStringBuilder.append("&initial_layout_class_list="); |
128 |
| - dataStringBuilder.append(String.join(" ", tokenOptions.getInitialLayoutClassList())); |
129 |
| - } |
130 |
| - |
131 |
| - long now = System.currentTimeMillis() / 1000L; |
132 |
| - if (expireTime == 0) { |
133 |
| - expireTime = now + (60*60*24); // 1 day |
134 |
| - } |
135 |
| - else if (expireTime < now) { |
| 110 | + String data = tokenOptions.getData(); |
| 111 | + int nonce = new Random().nextInt(); |
| 112 | + long iat = System.currentTimeMillis() / 1000; |
| 113 | + long exp = tokenOptions.getExpireTime(); |
| 114 | + |
| 115 | + if (exp == 0) { |
| 116 | + exp = iat + (60 * 60 * 24); // 1 day |
| 117 | + } else if (exp < iat) { |
136 | 118 | throw new InvalidArgumentException(
|
137 |
| - "Expire time must be in the future. Relative time: "+ (expireTime - now) |
| 119 | + "Expire time must be in the future. Relative time: " + (exp - iat) |
138 | 120 | );
|
139 |
| - } |
140 |
| - else if (expireTime > (now + (60*60*24*30) /* 30 days */)) { |
| 121 | + } else if (exp > (iat + (60 * 60 * 24 * 30) /* 30 days */)) { |
141 | 122 | throw new InvalidArgumentException(
|
142 |
| - "Expire time must be in the next 30 days. Too large by "+ (expireTime - (now + (60*60*24*30))) |
| 123 | + "Expire time must be in the next 30 days. Too large by " + (exp - (iat + (60 * 60 * 24 * 30))) |
143 | 124 | );
|
144 | 125 | }
|
145 |
| - // NOTE: Double.toString() would print the value with scientific notation |
146 |
| - dataStringBuilder.append(String.format("&expire_time=%.0f", expireTime)); |
147 | 126 |
|
148 |
| - if (data != null) { |
149 |
| - if (data.length() > 1000) { |
150 |
| - throw new InvalidArgumentException( |
151 |
| - "Connection data must be less than 1000 characters. length: " + data.length() |
152 |
| - ); |
| 127 | + if (tokenOptions.isLegacyT1Token()) { |
| 128 | + // Token format |
| 129 | + // |
| 130 | + // | ------------------------------ tokenStringBuilder ----------------------------- | |
| 131 | + // | "T1=="+Base64Encode(| --------------------- innerBuilder --------------------- |)| |
| 132 | + // | "partner_id={apiKey}&sig={sig}:| -- dataStringBuilder -- | |
| 133 | + |
| 134 | + StringBuilder dataStringBuilder = new StringBuilder() |
| 135 | + .append("session_id=").append(sessionId) |
| 136 | + .append("&create_time=").append(iat) |
| 137 | + .append("&nonce=").append(nonce) |
| 138 | + .append("&role=").append(role); |
| 139 | + |
| 140 | + if (tokenOptions.getInitialLayoutClassList() != null) { |
| 141 | + dataStringBuilder |
| 142 | + .append("&initial_layout_class_list=") |
| 143 | + .append(String.join(" ", tokenOptions.getInitialLayoutClassList())); |
153 | 144 | }
|
154 |
| - dataStringBuilder.append("&connection_data="); |
155 |
| - try { |
156 |
| - dataStringBuilder.append(URLEncoder.encode(data, "UTF-8")); |
157 |
| - } |
158 |
| - catch (UnsupportedEncodingException e) { |
159 |
| - throw new InvalidArgumentException( |
160 |
| - "Error during URL encode of your connection data: " + e.getMessage() |
161 |
| - ); |
162 |
| - } |
163 |
| - } |
164 |
| - |
165 | 145 |
|
166 |
| - StringBuilder tokenStringBuilder = new StringBuilder(); |
167 |
| - try { |
168 |
| - tokenStringBuilder.append("T1=="); |
| 146 | + dataStringBuilder.append("&expire_time=").append(exp); |
| 147 | + |
| 148 | + if (data != null) { |
| 149 | + if (data.length() > 1000) { |
| 150 | + throw new InvalidArgumentException( |
| 151 | + "Connection data must be less than 1000 characters. length: " + data.length() |
| 152 | + ); |
| 153 | + } |
| 154 | + dataStringBuilder.append("&connection_data="); |
| 155 | + try { |
| 156 | + dataStringBuilder.append(URLEncoder.encode(data, "UTF-8")); |
| 157 | + } |
| 158 | + catch (UnsupportedEncodingException e) { |
| 159 | + throw new InvalidArgumentException( |
| 160 | + "Error during URL encode of your connection data: " + e.getMessage() |
| 161 | + ); |
| 162 | + } |
| 163 | + } |
169 | 164 |
|
170 |
| - String innerBuilder = "partner_id=" + |
171 |
| - this.apiKey + |
172 |
| - "&sig=" + |
173 |
| - Crypto.signData(dataStringBuilder.toString(), this.apiSecret) + |
174 |
| - ":" + |
175 |
| - dataStringBuilder; |
176 | 165 |
|
177 |
| - tokenStringBuilder.append( |
178 |
| - Base64.encodeBase64String(innerBuilder.getBytes(StandardCharsets.UTF_8)) |
179 |
| - .replace("+", "-") |
180 |
| - .replace("/", "_") |
181 |
| - ); |
| 166 | + StringBuilder tokenStringBuilder = new StringBuilder(); |
| 167 | + try { |
| 168 | + tokenStringBuilder.append("T1=="); |
| 169 | + |
| 170 | + String innerBuilder = "partner_id=" + |
| 171 | + this.apiKey + |
| 172 | + "&sig=" + |
| 173 | + Crypto.signData(dataStringBuilder.toString(), this.apiSecret) + |
| 174 | + ":" + |
| 175 | + dataStringBuilder; |
| 176 | + |
| 177 | + tokenStringBuilder.append( |
| 178 | + Base64.encodeBase64String(innerBuilder.getBytes(StandardCharsets.UTF_8)) |
| 179 | + .replace("+", "-") |
| 180 | + .replace("/", "_") |
| 181 | + ); |
182 | 182 |
|
| 183 | + } |
| 184 | + catch (SignatureException | NoSuchAlgorithmException | InvalidKeyException e) { |
| 185 | + throw new OpenTokException("Could not generate token, a signing error occurred.", e); |
| 186 | + } |
| 187 | + return tokenStringBuilder.toString(); |
183 | 188 | }
|
184 |
| - catch (SignatureException | NoSuchAlgorithmException | InvalidKeyException e) { |
185 |
| - throw new OpenTokException("Could not generate token, a signing error occurred.", e); |
| 189 | + else { |
| 190 | + JwtClaims claims = new JwtClaims(); |
| 191 | + claims.setClaim("nonce", nonce); |
| 192 | + claims.setClaim("role", role.toString()); |
| 193 | + claims.setClaim("session_id", sessionId); |
| 194 | + claims.setClaim("scope", "session.connect"); |
| 195 | + if (tokenOptions.getInitialLayoutClassList() != null) { |
| 196 | + claims.setClaim("initial_layout_class_list", |
| 197 | + String.join(" ", tokenOptions.getInitialLayoutClassList()) |
| 198 | + ); |
| 199 | + } |
| 200 | + if (tokenOptions.getData() != null) { |
| 201 | + claims.setClaim("connection_data", tokenOptions.getData()); |
| 202 | + } |
| 203 | + return TokenGenerator.generateToken(claims, exp, apiKey, apiSecret); |
186 | 204 | }
|
187 |
| - |
188 |
| - return tokenStringBuilder.toString(); |
189 | 205 | }
|
190 | 206 | }
|
0 commit comments