diff --git a/build.gradle b/build.gradle index b948373..b769aa2 100644 --- a/build.gradle +++ b/build.gradle @@ -28,6 +28,7 @@ dependencies { testImplementation 'io.jsonwebtoken:jjwt-impl:0.12.6' testImplementation 'io.jsonwebtoken:jjwt-jackson:0.12.6' + implementation 'com.vonage:jwt:2.0.0' implementation 'commons-lang:commons-lang:2.6' implementation 'commons-codec:commons-codec:1.17.1' implementation 'io.netty:netty-codec-http:4.1.114.Final' @@ -68,6 +69,7 @@ javadoc { options { locale 'en_US' setMemberLevel JavadocMemberLevel.PUBLIC + addBooleanOption('Xdoclint:none', true) } } @@ -96,6 +98,12 @@ java { withJavadocJar() } +test { + testLogging { + exceptionFormat = 'full' + } +} + publishing { publications { mavenJava(MavenPublication) { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b82aa23..94113f2 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/src/main/java/com/opentok/CreatedSession.java b/src/main/java/com/opentok/CreatedSession.java index 92cbb19..00ec829 100644 --- a/src/main/java/com/opentok/CreatedSession.java +++ b/src/main/java/com/opentok/CreatedSession.java @@ -7,15 +7,14 @@ */ package com.opentok; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.ObjectMapper; /** * Used internally. */ @JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) public class CreatedSession { private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); @@ -26,6 +25,9 @@ public class CreatedSession { @JsonProperty("project_id") private String projectId; + @JsonProperty("application_id") + private String applicationId; + @JsonProperty("partner_id") private String partnerId; @@ -55,6 +57,10 @@ public String getProjectId() { return projectId; } + public String getApplicationId() { + return applicationId; + } + public String getPartnerId() { return partnerId; } diff --git a/src/main/java/com/opentok/Hls.java b/src/main/java/com/opentok/Hls.java index bb57f0f..b52b4d6 100644 --- a/src/main/java/com/opentok/Hls.java +++ b/src/main/java/com/opentok/Hls.java @@ -9,7 +9,7 @@ /** * Represents HLS options for a live streaming broadcast. Pass this object - * into the {@link BroadcastProperties.Builder#hls()} method. It is returned by the + * into the {@link BroadcastProperties.Builder#hls(Hls)} method. It is returned by the * {@link BroadcastProperties#hls()} method. */ public class Hls { diff --git a/src/main/java/com/opentok/OpenTok.java b/src/main/java/com/opentok/OpenTok.java index e0273b9..1af74fb 100644 --- a/src/main/java/com/opentok/OpenTok.java +++ b/src/main/java/com/opentok/OpenTok.java @@ -19,12 +19,14 @@ import com.opentok.util.HttpClient; import com.opentok.util.HttpClient.ProxyAuthScheme; import org.apache.commons.lang.StringUtils; - import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.Proxy; +import java.nio.file.Path; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.UUID; /** * Contains methods for creating OpenTok sessions, generating tokens, and working with archives. @@ -37,9 +39,9 @@ * Be sure to include the entire OpenTok server SDK on your web server. */ public class OpenTok { - private final int apiKey; - private final String apiSecret; + private final String apiSecret, applicationId; + private final Path privateKeyPath; protected HttpClient client; protected static final ObjectReader @@ -55,8 +57,6 @@ public class OpenTok { connectReader = new ObjectMapper().readerFor(AudioConnector.class), captionReader = new ObjectMapper().readerFor(Caption.class); - static final String defaultApiUrl = "https://api.opentok.com"; - /** * Creates an OpenTok object. * @@ -64,12 +64,30 @@ public class OpenTok { * @param apiSecret Your OpenTok API secret. (See your Vonage Video API account page.) */ public OpenTok(int apiKey, String apiSecret) { - this(apiKey, apiSecret, new HttpClient.Builder(apiKey, apiSecret).build()); + this(apiKey, apiSecret, null, null, new HttpClient.Builder(apiKey, apiSecret).build()); + } + + /** + * Creates an OpenTok object for use with the + * Vonage Video API. This is intended as a short-term step + * towards full migration to Vonage. See the + * Java SDK transition guide + * for details. + * + * @param applicationId Your Vonage application UUID with video capabilities enabled. + * @param privateKeyPath Absolute path to the private key for your application. + * + * @since 4.15.0 + */ + public OpenTok(String applicationId, Path privateKeyPath) { + this(0, null, applicationId, privateKeyPath, new HttpClient.Builder(applicationId, privateKeyPath).build()); } - private OpenTok(int apiKey, String apiSecret, HttpClient httpClient) { + private OpenTok(int apiKey, String apiSecret, String applicationId, Path privateKeyPath, HttpClient httpClient) { this.apiKey = apiKey; - this.apiSecret = apiSecret.trim(); + this.apiSecret = apiSecret != null ? apiSecret.trim() : null; + this.applicationId = applicationId; + this.privateKeyPath = privateKeyPath; this.client = httpClient; } @@ -85,7 +103,7 @@ private OpenTok(int apiKey, String apiSecret, HttpClient httpClient) { * import com.opentok.TokenOptions; * * class Test { - * public static void main(String argv[]) throws OpenTokException { + * public static void main(String args[]) throws OpenTokException { * int API_KEY = 0; // Replace with your OpenTok API key (see https://tokbox.com/account). * String API_SECRET = ""; // Replace with your OpenTok API secret. * OpenTok sdk = new OpenTok(API_KEY, API_SECRET); @@ -123,22 +141,28 @@ private OpenTok(int apiKey, String apiSecret, HttpClient httpClient) { * @return The token string. */ public String generateToken(String sessionId, TokenOptions tokenOptions) throws OpenTokException { - List sessionIdParts; + Session session; if (sessionId == null || sessionId.isEmpty()) { throw new InvalidArgumentException("Session not valid"); } - try { - sessionIdParts = Crypto.decodeSessionId(sessionId); - } catch (UnsupportedEncodingException e) { - throw new InvalidArgumentException("Session ID was not valid"); + if (privateKeyPath == null && apiSecret != null) { + List sessionIdParts; + try { + sessionIdParts = Crypto.decodeSessionId(sessionId); + } + catch (UnsupportedEncodingException e) { + throw new InvalidArgumentException("Session ID was not valid"); + } + if (!sessionIdParts.contains(Integer.toString(apiKey))) { + throw new InvalidArgumentException("Session ID was not valid"); + } + session = new Session(sessionId, apiKey, apiSecret); } - if (!sessionIdParts.contains(Integer.toString(apiKey))) { - throw new InvalidArgumentException("Session ID was not valid"); + else { + session = new Session(sessionId, applicationId, privateKeyPath); } - // NOTE: kind of wasteful of a Session instance - Session session = new Session(sessionId, apiKey, apiSecret); return session.generateToken(tokenOptions); } @@ -1036,15 +1060,11 @@ public void stopCaptions(String captionsId) throws OpenTokException { * {@link OpenTok OpenTok()} constructor to build the OpenTok object. */ public static class Builder { - private int apiKey; - private String apiSecret; - private String apiUrl; - private String appendUserAgent; + private int apiKey, requestTimeout; + private String apiSecret, applicationId, apiUrl, appendUserAgent, principal, password; + private Path privateKeyPath; private Proxy proxy; private ProxyAuthScheme proxyAuthScheme; - private String principal; - private String password; - private int requestTimeout; /** * Constructs a new OpenTok.Builder object. @@ -1060,6 +1080,13 @@ public Builder(int apiKey, String apiSecret) { this.apiSecret = apiSecret; } + public Builder(String applicationId, Path privateKeyPath) { + this.applicationId = UUID.fromString( + Objects.requireNonNull(applicationId, "Vonage Application ID is required") + ).toString(); + this.privateKeyPath = Objects.requireNonNull(privateKeyPath, "Private key path is required."); + } + /** * Do not use. This method is used by Vonage for testing. */ @@ -1113,7 +1140,7 @@ public Builder appendToUserAgent(String appendUserAgent) { * @return The OpenTok object. */ public OpenTok build() { - HttpClient.Builder clientBuilder = new HttpClient.Builder(apiKey, apiSecret); + HttpClient.Builder clientBuilder = new HttpClient.Builder(apiKey, apiSecret, applicationId, privateKeyPath); if (apiUrl != null) { clientBuilder.apiUrl(apiUrl); @@ -1128,7 +1155,7 @@ public OpenTok build() { clientBuilder.userAgent(DefaultUserAgent.DEFAULT_USER_AGENT+" "+appendUserAgent); } - return new OpenTok(apiKey, apiSecret, clientBuilder.build()); + return new OpenTok(apiKey, apiSecret, applicationId, privateKeyPath, clientBuilder.build()); } } diff --git a/src/main/java/com/opentok/Session.java b/src/main/java/com/opentok/Session.java index 914ef8c..ff621ee 100644 --- a/src/main/java/com/opentok/Session.java +++ b/src/main/java/com/opentok/Session.java @@ -11,9 +11,12 @@ import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; +import java.nio.file.Path; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SignatureException; +import java.util.LinkedHashMap; +import java.util.Map; import java.util.Random; import com.opentok.exception.InvalidArgumentException; @@ -29,9 +32,9 @@ * to get the session ID. */ public class Session { - private String sessionId; + private String sessionId, apiSecret, applicationId; + private Path privateKeyPath; private int apiKey; - private String apiSecret; private SessionProperties properties; protected Session(String sessionId, int apiKey, String apiSecret) { @@ -44,17 +47,38 @@ protected Session(String sessionId, int apiKey, String apiSecret, SessionPropert this.apiSecret = apiSecret; this.properties = properties; } - + + protected Session(String sessionId, String applicationId, Path privateKeyPath) { + this(sessionId, applicationId, privateKeyPath, new SessionProperties.Builder().build()); + } + + protected Session(String sessionId, String applicationId, Path privateKeyPath, SessionProperties properties) { + this.sessionId = sessionId; + this.properties = properties; + this.applicationId = applicationId; + this.privateKeyPath = privateKeyPath; + } + /** - * Returns the OpenTok API key used to generate the session. - */ + * Gets the Vonage application ID, if applicable. + * + * @return The Vonage application UUID as a string, or {@code null} if using OpenTok API key and secret. + * @since 4.15.0 + */ + public String getApplicationId() { + return applicationId; + } + + /** + * Returns the OpenTok API key used to generate the session. + */ public int getApiKey() { return apiKey; } /** - * Returns the session ID, which uniquely identifies the session. - */ + * Returns the session ID, which uniquely identifies the session. + */ public String getSessionId() { return sessionId; } @@ -124,6 +148,30 @@ public String generateToken(TokenOptions tokenOptions) throws OpenTokException { ); } + Map claims = new LinkedHashMap<>(); + claims.put("session_id", sessionId); + claims.put("nonce", nonce); + claims.put("role", role.toString()); + claims.put("scope", "session.connect"); + if (tokenOptions.getInitialLayoutClassList() != null) { + claims.put("initial_layout_class_list", String.join(" ", tokenOptions.getInitialLayoutClassList())); + } + if (data != null) { + if (data.length() > 1000) { + throw new InvalidArgumentException( + "Connection data must be less than 1000 characters. length: " + data.length() + ); + } + try { + claims.put("connection_data", tokenOptions.isLegacyT1Token() ? URLEncoder.encode(data, "UTF-8") : data); + } + catch (UnsupportedEncodingException e) { + throw new InvalidArgumentException( + "Error during URL encode of your connection data: " + e.getMessage() + ); + } + } + if (tokenOptions.isLegacyT1Token()) { // Token format // @@ -132,34 +180,11 @@ public String generateToken(TokenOptions tokenOptions) throws OpenTokException { // | "partner_id={apiKey}&sig={sig}:| -- dataStringBuilder -- | StringBuilder dataStringBuilder = new StringBuilder() - .append("session_id=").append(sessionId) - .append("&create_time=").append(iat) - .append("&nonce=").append(nonce) - .append("&role=").append(role); - - if (tokenOptions.getInitialLayoutClassList() != null) { - dataStringBuilder - .append("&initial_layout_class_list=") - .append(String.join(" ", tokenOptions.getInitialLayoutClassList())); - } + .append("create_time=").append(iat) + .append("&expire_time=").append(exp); - dataStringBuilder.append("&expire_time=").append(exp); - - if (data != null) { - if (data.length() > 1000) { - throw new InvalidArgumentException( - "Connection data must be less than 1000 characters. length: " + data.length() - ); - } - dataStringBuilder.append("&connection_data="); - try { - dataStringBuilder.append(URLEncoder.encode(data, "UTF-8")); - } - catch (UnsupportedEncodingException e) { - throw new InvalidArgumentException( - "Error during URL encode of your connection data: " + e.getMessage() - ); - } + for (Map.Entry entry : claims.entrySet()) { + dataStringBuilder.append('&').append(entry.getKey()).append('=').append(entry.getValue()); } @@ -186,21 +211,18 @@ public String generateToken(TokenOptions tokenOptions) throws OpenTokException { } return tokenStringBuilder.toString(); } - else { - JwtClaims claims = new JwtClaims(); - claims.setClaim("nonce", nonce); - claims.setClaim("role", role.toString()); - claims.setClaim("session_id", sessionId); - claims.setClaim("scope", "session.connect"); - if (tokenOptions.getInitialLayoutClassList() != null) { - claims.setClaim("initial_layout_class_list", - String.join(" ", tokenOptions.getInitialLayoutClassList()) - ); + else if (applicationId == null && privateKeyPath == null && apiKey != 0 && apiSecret != null) { + JwtClaims jwtClaims = new JwtClaims(); + for (Map.Entry entry : claims.entrySet()) { + jwtClaims.setClaim(entry.getKey(), entry.getValue()); } - if (tokenOptions.getData() != null) { - claims.setClaim("connection_data", tokenOptions.getData()); - } - return TokenGenerator.generateToken(claims, exp, apiKey, apiSecret); + return TokenGenerator.generateToken(jwtClaims, exp, apiKey, apiSecret); + } + else if (applicationId != null && privateKeyPath != null) { + return TokenGenerator.generateToken(claims, exp, applicationId, privateKeyPath); + } + else { + throw new IllegalStateException("Insufficient auth credentials."); } } } diff --git a/src/main/java/com/opentok/constants/DefaultApiUrl.java b/src/main/java/com/opentok/constants/DefaultApiUrl.java index 05840fd..f1a6660 100644 --- a/src/main/java/com/opentok/constants/DefaultApiUrl.java +++ b/src/main/java/com/opentok/constants/DefaultApiUrl.java @@ -9,5 +9,6 @@ public class DefaultApiUrl { public static final String DEFAULT_API_URI = "https://api.opentok.com"; + public static final String VONAGE_API_URL = "https://video.api.vonage.com"; } diff --git a/src/main/java/com/opentok/util/HttpClient.java b/src/main/java/com/opentok/util/HttpClient.java index 750a8c0..3d074df 100644 --- a/src/main/java/com/opentok/util/HttpClient.java +++ b/src/main/java/com/opentok/util/HttpClient.java @@ -20,6 +20,7 @@ import com.opentok.exception.InvalidArgumentException; import com.opentok.exception.OpenTokException; import com.opentok.exception.RequestException; +import com.vonage.jwt.Jwt; import org.apache.commons.lang.StringUtils; import org.asynchttpclient.*; import org.asynchttpclient.Realm.AuthScheme; @@ -27,23 +28,28 @@ import org.asynchttpclient.filter.FilterException; import org.asynchttpclient.filter.RequestFilter; import org.asynchttpclient.proxy.ProxyServer; - import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.net.InetSocketAddress; import java.net.Proxy; import java.net.SocketAddress; +import java.nio.file.Path; import java.util.*; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; +import java.util.function.Supplier; public class HttpClient extends DefaultAsyncHttpClient { - private final String apiUrl; - private final int apiKey; + private final String apiUrl, apiKey; private HttpClient(Builder builder) { super(builder.config); - this.apiKey = builder.apiKey; - this.apiUrl = builder.apiUrl; + apiKey = builder.apiKey; + apiUrl = builder.apiUrl; + } + + public String getApiUrl() { + return apiUrl; } public String createSession(Map> params) throws RequestException { @@ -67,7 +73,7 @@ public String createSession(Map> params) throws RequestExce } public String signal(String sessionId, String connectionId, SignalProperties properties) throws OpenTokException { - String url = this.apiUrl + "/v2/project/" + this.apiKey + "/session/" + sessionId + (connectionId != null && connectionId.length() > 0 ? "/connection/" + connectionId : "") + "/signal"; + String url = this.apiUrl + "/v2/project/" + this.apiKey + "/session/" + sessionId + (connectionId != null && !connectionId.isEmpty() ? "/connection/" + connectionId : "") + "/signal"; JsonNodeFactory nodeFactory = JsonNodeFactory.instance; ObjectNode requestJson = nodeFactory.objectNode(); @@ -1363,8 +1369,10 @@ public enum ProxyAuthScheme { } public static class Builder { - private final int apiKey; + private final String apiKey; private final String apiSecret; + private final Path privateKeyPath; + private final boolean vonage; private Proxy proxy; private ProxyAuthScheme proxyAuthScheme; private String principal; @@ -1375,8 +1383,22 @@ public static class Builder { private int requestTimeoutMS; public Builder(int apiKey, String apiSecret) { - this.apiKey = apiKey; + this(apiKey, apiSecret, null, null); + } + + public Builder(String applicationId, Path privateKeyPath) { + this(UUID.fromString(applicationId), privateKeyPath); + } + + public Builder(UUID applicationId, Path privateKeyPath) { + this(0, null, applicationId.toString(), privateKeyPath); + } + + public Builder(int apiKey, String apiSecret, String applicationId, Path privateKeyPath) { + vonage = applicationId != null; + this.apiKey = vonage ? applicationId : apiKey + ""; this.apiSecret = apiSecret; + this.privateKeyPath = privateKeyPath; } public Builder apiUrl(String apiUrl) { @@ -1423,10 +1445,13 @@ public Builder userAgent(String userAgent) { public HttpClient build() { DefaultAsyncHttpClientConfig.Builder configBuilder = new DefaultAsyncHttpClientConfig.Builder() .setUserAgent(userAgent) - .addRequestFilter(new TokenAuthRequestFilter(apiKey, apiSecret)); + .addRequestFilter(vonage ? + new TokenAuthRequestFilter(UUID.fromString(apiKey), privateKeyPath) : + new TokenAuthRequestFilter(Integer.parseInt(apiKey), apiSecret) + ); if (apiUrl == null) { - apiUrl = DefaultApiUrl.DEFAULT_API_URI; + apiUrl = vonage ? DefaultApiUrl.VONAGE_API_URL : DefaultApiUrl.DEFAULT_API_URI; } if (proxy != null) { configBuilder.setProxyServer(createProxyServer(proxy, proxyAuthScheme, principal, password)); @@ -1491,29 +1516,32 @@ static ProxyServer createProxyServer(final Proxy proxy, ProxyAuthScheme proxyAut } static class TokenAuthRequestFilter implements RequestFilter { - - private final int apiKey; - private final String apiSecret; - private final String authHeader = "X-OPENTOK-AUTH"; + private final Supplier tokenGenerator; + private final String headerName; public TokenAuthRequestFilter(int apiKey, String apiSecret) { - this.apiKey = apiKey; - this.apiSecret = apiSecret; + headerName = "X-OPENTOK-AUTH"; + tokenGenerator = () -> TokenGenerator.generateToken(apiKey, apiSecret); } - @Override - public FilterContext filter(FilterContext ctx) throws FilterException { + public TokenAuthRequestFilter(UUID applicationId, Path privateKeyPath) { + headerName = "Authorization"; try { - return new FilterContext.FilterContextBuilder<>(ctx) - .request(ctx.getRequest().toBuilder() - .addHeader(authHeader, TokenGenerator.generateToken(apiKey, apiSecret)) - .build() - ) - .build(); - } catch (OpenTokException e) { - e.printStackTrace(); - return null; + Jwt jwtGenerator = Jwt.builder().applicationId(applicationId).privateKeyPath(privateKeyPath).build(); + tokenGenerator = () -> "Bearer " + jwtGenerator.generate(); + } + catch (IOException ex) { + throw new InvalidArgumentException("Could not create a JWT generator: " + ex); } } + + @Override + public FilterContext filter(FilterContext ctx) throws FilterException { + return new FilterContext.FilterContextBuilder<>(ctx) + .request(ctx.getRequest().toBuilder() + .addHeader(headerName, tokenGenerator.get()) + .build() + ).build(); + } } } diff --git a/src/main/java/com/opentok/util/TokenGenerator.java b/src/main/java/com/opentok/util/TokenGenerator.java index 4fcdd31..3b7ab88 100644 --- a/src/main/java/com/opentok/util/TokenGenerator.java +++ b/src/main/java/com/opentok/util/TokenGenerator.java @@ -8,14 +8,18 @@ package com.opentok.util; import com.opentok.exception.OpenTokException; +import com.vonage.jwt.Jwt; import org.jose4j.jws.AlgorithmIdentifiers; import org.jose4j.jws.JsonWebSignature; import org.jose4j.jwt.JwtClaims; import org.jose4j.jwt.NumericDate; import org.jose4j.lang.JoseException; import javax.crypto.spec.SecretKeySpec; +import java.io.IOException; +import java.nio.file.Path; import java.time.Instant; import java.time.temporal.ChronoUnit; +import java.util.Map; public class TokenGenerator { @@ -36,6 +40,21 @@ public static String generateToken(final Integer apiKey, final String apiSecret) return generateToken(claims, defaultExpireTime, apiKey, apiSecret); } + public static String generateToken(Map claims, final long expireTime, + final String applicationId, final Path privateKeyPath) throws OpenTokException { + try { + claims.put(EXP, expireTime); + return Jwt.builder() + .applicationId(applicationId) + .privateKeyPath(privateKeyPath) + .claims(claims) + .build().generate(); + } + catch (IOException ex) { + throw new OpenTokException("Could not generate token: " + ex.getMessage()); + } + } + public static String generateToken(final JwtClaims claims, final long expireTime, final int apiKey, final String apiSecret) throws OpenTokException { final SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(), diff --git a/src/test/java/com/opentok/test/OpenTokTest.java b/src/test/java/com/opentok/OpenTokTest.java similarity index 92% rename from src/test/java/com/opentok/test/OpenTokTest.java rename to src/test/java/com/opentok/OpenTokTest.java index 1c993cf..741b234 100644 --- a/src/test/java/com/opentok/test/OpenTokTest.java +++ b/src/test/java/com/opentok/OpenTokTest.java @@ -5,7 +5,7 @@ * * Licensed under The MIT License (MIT). See LICENSE file for more information. */ -package com.opentok.test; +package com.opentok; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -14,31 +14,30 @@ import static com.github.tomakehurst.wiremock.client.WireMock.matching; import com.github.tomakehurst.wiremock.core.WireMockConfiguration; import com.github.tomakehurst.wiremock.junit.WireMockRule; -import com.opentok.*; import com.opentok.Archive.OutputMode; import com.opentok.constants.DefaultUserAgent; import com.opentok.exception.InvalidArgumentException; import com.opentok.exception.OpenTokException; import com.opentok.exception.RequestException; -import io.jsonwebtoken.JwtParserBuilder; import io.jsonwebtoken.Jwts; import org.apache.commons.lang.StringUtils; -import org.jose4j.jwt.consumer.JwtConsumer; -import org.jose4j.jwt.consumer.JwtConsumerBuilder; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import java.io.UnsupportedEncodingException; import java.net.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.security.InvalidKeyException; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.SignatureException; import java.security.spec.X509EncodedKeySpec; import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.*; -import java.util.stream.Collectors; import static com.github.tomakehurst.wiremock.client.WireMock.*; import static org.junit.Assert.*; @@ -106,13 +105,13 @@ public void testUserAgent() throws Exception { public void testConfigureRequestTimeout() { assertThrows(RequestException.class, () -> { sdk.close(); - sdk = new OpenTok.Builder(apiKey, apiSecret).apiUrl(apiUrl).requestTimeout(6).build(); + sdk = new OpenTok.Builder(apiKey, apiSecret).apiUrl(apiUrl).requestTimeout(3).build(); String sessionId = "SESSIONID"; stubFor(post(urlEqualTo(SESSION_CREATE)) .willReturn(aResponse() .withStatus(200) - .withFixedDelay(7000) + .withFixedDelay(3200) .withHeader("Content-Type", "application/json") .withBody("[{\"session_id\":\"" + sessionId + "\",\"project_id\":\"00000000\"," + "\"partner_id\":\"123456\"," + @@ -149,9 +148,9 @@ public void testSignalAllConnections() throws OpenTokException { verify(postRequestedFor(urlMatching(path)) .withRequestBody(equalToJson("{ \"type\":\"test\",\"data\":\"Signal test string\" }"))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(path))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -190,9 +189,9 @@ public void testSignalSingleConnection() throws OpenTokException { verify(postRequestedFor(urlMatching(path)) .withRequestBody(equalToJson("{ \"type\":\"test\",\"data\":\"Signal test string\" }"))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(path))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -261,9 +260,9 @@ public void testCreateDefaultSession() throws OpenTokException { verify(postRequestedFor(urlMatching(SESSION_CREATE)) .withRequestBody(matching(".*p2p.preference=enabled.*")) .withRequestBody(matching(".*archiveMode=manual.*"))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(SESSION_CREATE))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -294,9 +293,9 @@ public void testCreateRoutedSession() throws OpenTokException { verify(postRequestedFor(urlMatching(SESSION_CREATE)) // NOTE: this is a pretty bad way to verify, ideally we can decode the body and then query the object .withRequestBody(matching(".*p2p.preference=disabled.*"))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(SESSION_CREATE))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -328,9 +327,9 @@ public void testCreateLocationHintSession() throws OpenTokException { verify(postRequestedFor(urlMatching(SESSION_CREATE)) // TODO: this is a pretty bad way to verify, ideally we can decode the body and then query the object .withRequestBody(matching(".*location=" + locationHint + ".*"))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(SESSION_CREATE))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -363,9 +362,9 @@ public void testCreateEncryptedSession() throws OpenTokException { verify(postRequestedFor(urlMatching(SESSION_CREATE)) // NOTE: this is a pretty bad way to verify, ideally we can decode the body and then query the object .withRequestBody(matching(".*e2ee=true.*"))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(SESSION_CREATE))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -399,9 +398,9 @@ public void testCreateAlwaysArchivedSession() throws OpenTokException { .withRequestBody(matching(".*archiveMode=always.*")) .withRequestBody(matching(".*archiveResolution=720x1280.*")) .withRequestBody(matching(".*archiveName=720pTest.*"))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(SESSION_CREATE))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -536,9 +535,9 @@ public void testLegacyTokenDefault() throws String token = sdk.generateToken(sessionId, new TokenOptions.Builder().useLegacyT1Token().build()); assertNotNull(token); - assertTrue(Helpers.verifyTokenSignature(token, apiSecret)); + assertTrue(TestHelpers.verifyTokenSignature(token, apiSecret)); - Map tokenData = Helpers.decodeToken(token); + Map tokenData = TestHelpers.decodeToken(token); assertEquals(Integer.toString(apiKey), tokenData.get("partner_id")); assertNotNull(tokenData.get("create_time")); assertNotNull(tokenData.get("nonce")); @@ -553,9 +552,9 @@ public void testLegacyTokenLayoutClass() throws .initialLayoutClassList(Arrays.asList("full", "focus")).useLegacyT1Token().build()); assertNotNull(token); - assertTrue(Helpers.verifyTokenSignature(token, apiSecret)); + assertTrue(TestHelpers.verifyTokenSignature(token, apiSecret)); - Map tokenData = Helpers.decodeToken(token); + Map tokenData = TestHelpers.decodeToken(token); assertEquals("full focus", tokenData.get("initial_layout_class_list")); } @@ -580,8 +579,8 @@ public void testLegacyTokenRoles() throws Exception { ); assertNotNull(roleToken); - assertTrue(Helpers.verifyTokenSignature(roleToken, apiSecret)); - Map roleTokenData = Helpers.decodeToken(roleToken); + assertTrue(TestHelpers.verifyTokenSignature(roleToken, apiSecret)); + Map roleTokenData = TestHelpers.decodeToken(roleToken); assertEquals(role.toString(), roleTokenData.get("role")); } } @@ -612,8 +611,8 @@ public void testLegacyTokenExpireTime() throws } assertNotNull(oneHourToken); - assertTrue(Helpers.verifyTokenSignature(oneHourToken, apiSecret)); - Map oneHourTokenData = Helpers.decodeToken(oneHourToken); + assertTrue(TestHelpers.verifyTokenSignature(oneHourToken, apiSecret)); + Map oneHourTokenData = TestHelpers.decodeToken(oneHourToken); assertEquals(Long.toString(inOneHour), oneHourTokenData.get("expire_time")); assertEquals(2, exceptions.size()); for (Exception e : exceptions) { @@ -639,8 +638,8 @@ public void testLegacyTokenConnectionData() throws } assertNotNull(dataBearingToken); - assertTrue(Helpers.verifyTokenSignature(dataBearingToken, apiSecret)); - Map dataBearingTokenData = Helpers.decodeToken(dataBearingToken); + assertTrue(TestHelpers.verifyTokenSignature(dataBearingToken, apiSecret)); + Map dataBearingTokenData = TestHelpers.decodeToken(dataBearingToken); assertEquals(actualData, dataBearingTokenData.get("connection_data")); assertEquals(InvalidArgumentException.class, tooLongException.getClass()); } @@ -678,6 +677,10 @@ public void testTokenBadSessionId() throws OpenTokException { @Test public void testGetArchive() throws OpenTokException { String archiveId = "ARCHIVEID"; + String url = "http://tokbox.com.archive2.s3.amazonaws.com/123456%2F" + archiveId + + "%2Farchive.mp4?Expires=13951" + + "94362&Signature=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; + stubFor(get(urlEqualTo(archivePath + "/" + archiveId)) .willReturn(aResponse() .withStatus(200) @@ -692,9 +695,7 @@ public void testGetArchive() throws OpenTokException { " \"sessionId\" : \"SESSIONID\",\n" + " \"size\" : 8347554,\n" + " \"status\" : \"available\",\n" + - " \"url\" : \"http://tokbox.com.archive2.s3.amazonaws.com/123456%2F" + - archiveId + "%2Farchive.mp4?Expires=1395194362&kid=AKIAI6LQCPIXYVWCQV6Q&Si" + - "gnature=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n" + + " \"url\" : \""+url+"\"\n" + " }"))); Archive archive = sdk.getArchive(archiveId); @@ -714,13 +715,12 @@ public void testGetArchive() throws OpenTokException { assertEquals("SESSIONID", archive.getSessionId()); assertEquals(8347554, archive.getSize()); assertEquals(Archive.Status.AVAILABLE, archive.getStatus()); - assertEquals("http://tokbox.com.archive2.s3.amazonaws.com/123456%2F" + archiveId + "%2Farchive.mp4?Expires=13951" + - "94362&kid=AKIAI6LQCPIXYVWCQV6Q&Signature=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", archive.getUrl()); + assertEquals(url, archive.getUrl()); verify(getRequestedFor(urlMatching(archivePath + "/" + archiveId))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(getRequestedFor(urlMatching(archivePath + "/" + archiveId))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -731,9 +731,9 @@ public void testPatchArchive() throws OpenTokException { .willReturn(aResponse().withStatus(204))); sdk.addArchiveStream(archiveId, streamId, true, true); verify(patchRequestedFor(urlMatching(archivePath + "/" + archiveId + "/streams"))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(deleteRequestedFor(urlMatching(archivePath + "/" + archiveId))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -748,6 +748,7 @@ public void testPatchArchiveExpectException() throws OpenTokException { // TODO: test get archive failure scenarios @Test public void testListArchives() throws OpenTokException { + String url = "http://tokbox.com.archive2.s3.amazonaws.com/123456d%2Farchive.mp4?Expires=1395188695"; stubFor(get(urlEqualTo(archivePath)) .willReturn(aResponse() .withStatus(200) @@ -764,9 +765,7 @@ public void testListArchives() throws OpenTokException { " \"sessionId\" : \"SESSIONID\",\n" + " \"size\" : 247145329511,\n" + " \"status\" : \"available\",\n" + - " \"url\" : \"http://tokbox.com.archive2.s3.amazonaws.com/123456%2Fef546c5" + - "a-4fd7-4e59-ab3d-f1cfb4148d1d%2Farchive.mp4?Expires=1395188695&kid=AKIAI6" + - "LQCPIXYVWCQV6Q&Signature=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n" + + " \"url\" : \""+url+"\"\n" + " }, {\n" + " \"createdAt\" : 1395187910000,\n" + " \"duration\" : 14,\n" + @@ -778,9 +777,7 @@ public void testListArchives() throws OpenTokException { " \"sessionId\" : \"SESSIONID\",\n" + " \"size\" : 1952651,\n" + " \"status\" : \"available\",\n" + - " \"url\" : \"http://tokbox.com.archive2.s3.amazonaws.com/123456%2F5350f06" + - "f-0166-402e-bc27-09ba54948512%2Farchive.mp4?Expires=1395188695&kid=AKIAI6" + - "LQCPIXYVWCQV6Q&Signature=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n" + + " \"url\" : \""+url+"\"\n" + " }, {\n" + " \"createdAt\" : 1395187836000,\n" + " \"duration\" : 62,\n" + @@ -791,9 +788,7 @@ public void testListArchives() throws OpenTokException { " \"sessionId\" : \"SESSIONID\",\n" + " \"size\" : 8347554,\n" + " \"status\" : \"available\",\n" + - " \"url\" : \"http://tokbox.com.archive2.s3.amazonaws.com/123456%2Ff6e7ee5" + - "8-d6cf-4a59-896b-6d56b158ec71%2Farchive.mp4?Expires=1395188695&kid=AKIAI6" + - "LQCPIXYVWCQV6Q&Signature=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n" + + " \"url\" : \""+url+"\"\n" + " }, {\n" + " \"createdAt\" : 1395183243000,\n" + " \"duration\" : 544,\n" + @@ -804,9 +799,7 @@ public void testListArchives() throws OpenTokException { " \"sessionId\" : \"SESSIONID\",\n" + " \"size\" : 78499758,\n" + " \"status\" : \"available\",\n" + - " \"url\" : \"http://tokbox.com.archive2.s3.amazonaws.com/123456%2F30b3ebf" + - "1-ba36-4f5b-8def-6f70d9986fe9%2Farchive.mp4?Expires=1395188695&kid=AKIAI6" + - "LQCPIXYVWCQV6Q&Signature=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n" + + " \"url\" : \""+url+"\"\n" + " }, {\n" + " \"createdAt\" : 1394396753000,\n" + " \"duration\" : 24,\n" + @@ -817,9 +810,7 @@ public void testListArchives() throws OpenTokException { " \"sessionId\" : \"SESSIONID\",\n" + " \"size\" : 2227849,\n" + " \"status\" : \"available\",\n" + - " \"url\" : \"http://tokbox.com.archive2.s3.amazonaws.com/123456%2Fb8f64de" + - "1-e218-4091-9544-4cbf369fc238%2Farchive.mp4?Expires=1395188695&kid=AKIAI6" + - "LQCPIXYVWCQV6Q&Signature=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n" + + " \"url\" : \""+url+"\"\n" + " }, {\n" + " \"createdAt\" : 1394321113000,\n" + " \"duration\" : 1294,\n" + @@ -830,9 +821,7 @@ public void testListArchives() throws OpenTokException { " \"sessionId\" : \"SESSIONID\",\n" + " \"size\" : 42165242,\n" + " \"status\" : \"available\",\n" + - " \"url\" : \"http://tokbox.com.archive2.s3.amazonaws.com/123456%2F832641b" + - "f-5dbf-41a1-ad94-fea213e59a92%2Farchive.mp4?Expires=1395188695&kid=AKIAI6" + - "LQCPIXYVWCQV6Q&Signature=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n" + + " \"url\" : \""+url+"\"\n" + " } ]\n" + " }"))); ArchiveList archives = sdk.listArchives(); @@ -843,14 +832,13 @@ public void testListArchives() throws OpenTokException { assertEquals("ef546c5a-4fd7-4e59-ab3d-f1cfb4148d1d", archives.get(0).getId()); assertEquals("MyVideoArchiveTag", archives.get(1).getMultiArchiveTag()); verify(getRequestedFor(urlMatching(archivePath))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(getRequestedFor(urlMatching(archivePath))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test public void testListArchivesWithOffSetCount() throws OpenTokException { - String sessionId = "SESSIONID"; String url = archivePath + "?offset=1&count=1"; stubFor(get(urlEqualTo(url)) .willReturn(aResponse() @@ -868,9 +856,7 @@ public void testListArchivesWithOffSetCount() throws OpenTokException { " \"sessionId\" : \"SESSIONID\",\n" + " \"size\" : 2909274,\n" + " \"status\" : \"available\",\n" + - " \"url\" : \"http://tokbox.com.archive2.s3.amazonaws.com/123456%2Fef546c5" + - "a-4fd7-4e59-ab3d-f1cfb4148d1d%2Farchive.mp4?Expires=1395188695&kid=AKIAI6" + - "LQCPIXYVWCQV6Q&Signature=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n" + + " \"url\" : \""+url+"\"\n" + " }]\n" + " }"))); @@ -882,9 +868,9 @@ public void testListArchivesWithOffSetCount() throws OpenTokException { assertEquals("ef546c5a-4fd7-4e59-ab3d-f1cfb4148d1d", archives.get(0).getId()); verify(getRequestedFor(urlEqualTo(url))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(getRequestedFor(urlMatching(url))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -907,9 +893,7 @@ public void testListArchivesWithSessionIdOffSetCount() throws OpenTokException { " \"sessionId\" : \"SESSIONID\",\n" + " \"size\" : 2909274,\n" + " \"status\" : \"available\",\n" + - " \"url\" : \"http://tokbox.com.archive2.s3.amazonaws.com/123456%2Fef546c5" + - "a-4fd7-4e59-ab3d-f1cfb4148d1d%2Farchive.mp4?Expires=1395188695&kid=AKIAI6" + - "LQCPIXYVWCQV6Q&Signature=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n" + + " \"url\" : \""+url+"\"\n" + " }]\n" + " }"))); ArchiveList archives = sdk.listArchives(sessionId, 1, 1); @@ -919,9 +903,9 @@ public void testListArchivesWithSessionIdOffSetCount() throws OpenTokException { assertNotNull(archives.get(0)); assertEquals("ef546c5a-4fd7-4e59-ab3d-f1cfb4148d1d", archives.get(0).getId()); verify(getRequestedFor(urlEqualTo(url))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(getRequestedFor(urlMatching(url))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -944,9 +928,7 @@ public void testListArchivesWithSessionId() throws OpenTokException { " \"sessionId\" : \"SESSIONID\",\n" + " \"size\" : 2909274,\n" + " \"status\" : \"available\",\n" + - " \"url\" : \"http://tokbox.com.archive2.s3.amazonaws.com/123456%2Fef546c5" + - "a-4fd7-4e59-ab3d-f1cfb4148d1d%2Farchive.mp4?Expires=1395188695&kid=AKIAI6" + - "LQCPIXYVWCQV6Q&Signature=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n" + + " \"url\" : \""+url+"\"\n" + " }, {\n" + " \"createdAt\" : 1395187910000,\n" + " \"duration\" : 14,\n" + @@ -957,9 +939,7 @@ public void testListArchivesWithSessionId() throws OpenTokException { " \"sessionId\" : \"SESSIONID\",\n" + " \"size\" : 1952651,\n" + " \"status\" : \"available\",\n" + - " \"url\" : \"http://tokbox.com.archive2.s3.amazonaws.com/123456%2F5350f06" + - "f-0166-402e-bc27-09ba54948512%2Farchive.mp4?Expires=1395188695&kid=AKIAI6" + - "LQCPIXYVWCQV6Q&Signature=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n" + + " \"url\" : \""+url+"\"\n" + " }, {\n" + " \"createdAt\" : 1395187836000,\n" + " \"duration\" : 62,\n" + @@ -970,9 +950,7 @@ public void testListArchivesWithSessionId() throws OpenTokException { " \"sessionId\" : \"SESSIONID\",\n" + " \"size\" : 8347554,\n" + " \"status\" : \"available\",\n" + - " \"url\" : \"http://tokbox.com.archive2.s3.amazonaws.com/123456%2Ff6e7ee5" + - "8-d6cf-4a59-896b-6d56b158ec71%2Farchive.mp4?Expires=1395188695&kid=AKIAI6" + - "LQCPIXYVWCQV6Q&Signature=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n" + + " \"url\" : \""+url+"\"\n" + " }, {\n" + " \"createdAt\" : 1395183243000,\n" + " \"duration\" : 544,\n" + @@ -983,9 +961,7 @@ public void testListArchivesWithSessionId() throws OpenTokException { " \"sessionId\" : \"SESSIONID\",\n" + " \"size\" : 78499758,\n" + " \"status\" : \"available\",\n" + - " \"url\" : \"http://tokbox.com.archive2.s3.amazonaws.com/123456%2F30b3ebf" + - "1-ba36-4f5b-8def-6f70d9986fe9%2Farchive.mp4?Expires=1395188695&kid=AKIAI6" + - "LQCPIXYVWCQV6Q&Signature=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n" + + " \"url\" : \""+url+"\"\n" + " }, {\n" + " \"createdAt\" : 1394396753000,\n" + " \"duration\" : 24,\n" + @@ -996,9 +972,7 @@ public void testListArchivesWithSessionId() throws OpenTokException { " \"sessionId\" : \"SESSIONID\",\n" + " \"size\" : 2227849,\n" + " \"status\" : \"available\",\n" + - " \"url\" : \"http://tokbox.com.archive2.s3.amazonaws.com/123456%2Fb8f64de" + - "1-e218-4091-9544-4cbf369fc238%2Farchive.mp4?Expires=1395188695&kid=AKIAI6" + - "LQCPIXYVWCQV6Q&Signature=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n" + + " \"url\" : \""+url+"\"\n" + " }, {\n" + " \"createdAt\" : 1394321113000,\n" + " \"duration\" : 1294,\n" + @@ -1009,9 +983,7 @@ public void testListArchivesWithSessionId() throws OpenTokException { " \"sessionId\" : \"SESSIONID\",\n" + " \"size\" : 42165242,\n" + " \"status\" : \"available\",\n" + - " \"url\" : \"http://tokbox.com.archive2.s3.amazonaws.com/123456%2F832641b" + - "f-5dbf-41a1-ad94-fea213e59a92%2Farchive.mp4?Expires=1395188695&kid=AKIAI6" + - "LQCPIXYVWCQV6Q&Signature=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n" + + " \"url\" : \""+url+"\"\n" + " } ]\n" + " }"))); ArchiveList archives = sdk.listArchives(sessionId); @@ -1021,9 +993,9 @@ public void testListArchivesWithSessionId() throws OpenTokException { assertNotNull(archives.get(0)); assertEquals("ef546c5a-4fd7-4e59-ab3d-f1cfb4148d1d", archives.get(0).getId()); verify(getRequestedFor(urlEqualTo(url))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(getRequestedFor(urlMatching(url))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -1112,9 +1084,9 @@ public void testStartArchive() throws OpenTokException { assertEquals(sessionId, archive.getSessionId()); assertNotNull(archive.getId()); verify(postRequestedFor(urlMatching(archivePath))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(archivePath))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -1150,9 +1122,9 @@ public void testStartArchiveWithScreenshareType() throws OpenTokException { assertEquals(sessionId, archive.getSessionId()); assertNotNull(archive.getId()); verify(postRequestedFor(urlMatching(archivePath)).withRequestBody(equalToJson(expectedJson))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(archivePath))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -1181,9 +1153,9 @@ public void testStartArchiveWithResolution() throws OpenTokException { assertEquals(sessionId, archive.getSessionId()); assertEquals(archive.getResolution(), "1280x720"); verify(postRequestedFor(urlMatching(archivePath))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(archivePath))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -1209,9 +1181,9 @@ public void testSetArchiveLayoutVertical() throws OpenTokException { sdk.setArchiveLayout(archiveId, properties); verify(putRequestedFor(urlMatching(url))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(putRequestedFor(urlMatching(url))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -1226,9 +1198,9 @@ public void testSetArchiveLayoutScreenshareType() throws OpenTokException { String expectedJson = "{\"type\":\"bestFit\",\"screenshareType\":\"pip\"}"; sdk.setArchiveLayout(archiveId, properties); verify(putRequestedFor(urlMatching(url)).withRequestBody(equalToJson(expectedJson))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(putRequestedFor(urlMatching(url))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -1256,8 +1228,8 @@ public void testSetArchiveLayoutCustom() throws OpenTokException { sdk.setArchiveLayout(archiveId, properties); verify(putRequestedFor(urlMatching(url))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, findAll(putRequestedFor(urlMatching(url))))); - Helpers.verifyUserAgent(); + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(putRequestedFor(urlMatching(url))))); + TestHelpers.verifyUserAgent(); } @Test @@ -1304,9 +1276,9 @@ public void testSetArchiveStreamsMultiLayout() throws OpenTokException { .withHeader("Content-Type", "application/json"))); sdk.setStreamLayouts(sessionId, properties); verify(putRequestedFor(urlMatching(url))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(putRequestedFor(urlMatching(url))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -1323,9 +1295,9 @@ public void testSetArchiveStreamsOneLayout() throws OpenTokException { .withHeader("Content-Type", "application/json"))); sdk.setStreamLayouts(sessionId, properties); verify(putRequestedFor(urlMatching(url))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(putRequestedFor(urlMatching(url))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -1342,9 +1314,9 @@ public void testSetArchiveStreamsNoLayout() throws OpenTokException { .withHeader("Content-Type", "application/json"))); sdk.setStreamLayouts(sessionId, properties); verify(putRequestedFor(urlMatching(url))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(putRequestedFor(urlMatching(url))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -1374,9 +1346,9 @@ public void testStartArchiveWithName() throws OpenTokException { assertEquals(name, archive.getName()); assertNotNull(archive.getId()); verify(postRequestedFor(urlMatching(archivePath))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(archivePath))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -1406,9 +1378,9 @@ public void testStartVoiceOnlyArchive() throws OpenTokException { assertEquals(sessionId, archive.getSessionId()); assertNotNull(archive.getId()); verify(postRequestedFor(urlMatching(archivePath))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(archivePath))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -1440,9 +1412,9 @@ public void testStartComposedArchive() throws OpenTokException { assertNotNull(archive.getId()); assertEquals(OutputMode.COMPOSED, archive.getOutputMode()); verify(postRequestedFor(urlMatching(archivePath))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(archivePath))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -1475,9 +1447,9 @@ public void testStartComposedArchiveWithLayout() throws OpenTokException { assertNotNull(archive.getId()); assertEquals(OutputMode.COMPOSED, archive.getOutputMode()); verify(postRequestedFor(urlMatching(archivePath))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(archivePath))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -1520,9 +1492,9 @@ public void testStartIndividualArchive() throws OpenTokException { assertNotNull(archive.getId()); assertEquals(OutputMode.INDIVIDUAL, archive.getOutputMode()); verify(postRequestedFor(urlMatching(archivePath))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(archivePath))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } // TODO: test start archive with name @@ -1554,9 +1526,9 @@ public void testStopArchive() throws OpenTokException { assertEquals("SESSIONID", archive.getSessionId()); assertEquals(archiveId, archive.getId()); verify(postRequestedFor(urlMatching(archivePath + "/" + archiveId + "/stop"))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(archivePath + "/" + archiveId + "/stop"))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } // TODO: test stop archive failure scenarios @@ -1571,9 +1543,9 @@ public void testDeleteArchive() throws OpenTokException { sdk.deleteArchive(archiveId); verify(deleteRequestedFor(urlMatching(archivePath + "/" + archiveId))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(deleteRequestedFor(urlMatching(archivePath + "/" + archiveId))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } // TODO: test delete archive failure scenarios @@ -1677,9 +1649,9 @@ public void testGetStreamWithId() throws OpenTokException { assertEquals("camera", stream.getVideoType()); verify(getRequestedFor(urlMatching(url))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(getRequestedFor(urlMatching(url))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -1691,8 +1663,8 @@ public void testForceMuteStream() throws OpenTokException { .willReturn(aResponse().withStatus(200))); sdk.forceMuteStream(sessionID, streamID); verify(postRequestedFor(urlMatching(path))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(path))))); - Helpers.verifyUserAgent(); + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(path))))); + TestHelpers.verifyUserAgent(); assertThrows(InvalidArgumentException.class, () -> sdk.forceMuteStream("", streamID)); assertThrows(InvalidArgumentException.class, () -> sdk.forceMuteStream(sessionID, "")); } @@ -1712,9 +1684,9 @@ public void testForceMuteAllStreamWithIdList() throws OpenTokException { .excludedStreamIds(excludedList).build(); sdk.forceMuteAll(sessionID, properties); verify(postRequestedFor(urlMatching(path))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(SESSION_CREATE))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); assertThrows(InvalidArgumentException.class, () -> sdk.forceMuteAll("", properties)); } @@ -1728,9 +1700,9 @@ public void testDisableForceMute() throws OpenTokException { .withHeader("Content-Type", "application/json"))); sdk.disableForceMute(sessionID); verify(postRequestedFor(urlMatching(path))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(SESSION_CREATE))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); assertThrows(InvalidArgumentException.class, () -> sdk.disableForceMute("")); } @@ -1769,9 +1741,9 @@ public void testListStreams() throws OpenTokException { assertEquals("screen", stream2.getVideoType()); verify(getRequestedFor(urlMatching(url))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(getRequestedFor(urlMatching(url))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -1881,9 +1853,9 @@ public void testStartBroadcast() throws OpenTokException { assertEquals(Broadcast.StreamMode.AUTO, broadcast.getStreamMode()); assertNotNull(broadcast.getId()); verify(postRequestedFor(urlMatching(url))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(url))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -1941,9 +1913,9 @@ public void testStartBroadcastHlsParameters() throws OpenTokException { .build(); Broadcast broadcast = sdk.startBroadcast(sessionId, properties); verify(postRequestedFor(urlMatching(broadcastPath))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(broadcastPath))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -1986,8 +1958,8 @@ public void testBroadcastWithScreenShareType() throws OpenTokException { assertEquals(sessionId, broadcast.getSessionId()); assertNotNull(broadcast.getId()); verify(postRequestedFor(urlMatching(broadcastPath)).withRequestBody(equalToJson(expectedJson))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(broadcastPath))))); - Helpers.verifyUserAgent(); + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(broadcastPath))))); + TestHelpers.verifyUserAgent(); } @Test @@ -2046,9 +2018,9 @@ public void testStartBroadcastWithCustomLayout() throws OpenTokException { assertEquals(sessionId, broadcast.getSessionId()); assertNotNull(broadcast.getId()); verify(postRequestedFor(urlMatching(broadcastPath))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(broadcastPath))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -2095,9 +2067,9 @@ public void testStartBroadcastNoHls() throws OpenTokException { assertNotNull(broadcast.getId()); assertNull(broadcast.getHls()); verify(postRequestedFor(urlMatching(broadcastPath))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(broadcastPath))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -2135,9 +2107,9 @@ public void testStartBroadcastNoRtmp() throws OpenTokException { assertNotNull(broadcast.getId()); assertTrue(broadcast.getRtmpList().isEmpty()); verify(postRequestedFor(urlMatching(broadcastPath))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(broadcastPath))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -2168,9 +2140,9 @@ public void testPatchBroadcast() throws OpenTokException { .willReturn(aResponse().withStatus(204))); sdk.addBroadcastStream(broadcastId, streamId, true, true); verify(patchRequestedFor(urlMatching(broadcastPath + "/" + broadcastId + "/streams"))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(deleteRequestedFor(urlMatching(archivePath + "/" + broadcastId))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -2203,9 +2175,9 @@ public void testStopBroadcast() throws OpenTokException { assertNotNull(broadcast); assertEquals(broadcastId, broadcast.getId()); verify(postRequestedFor(urlMatching(url))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(url))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -2245,9 +2217,9 @@ public void testBroadcastStreamInfo() throws OpenTokException { assertEquals("http://server/fakepath/playlist.m3u8", broadcast.getHls()); assertEquals(2, broadcast.getRtmpList().size()); verify(getRequestedFor(urlMatching(url))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(url))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); assertThrows(InvalidArgumentException.class, () -> sdk.getBroadcast("")); } @@ -2263,9 +2235,9 @@ public void testSetBroadcastLayoutVertical() throws OpenTokException { sdk.setBroadcastLayout(broadcastId, properties); verify(putRequestedFor(urlMatching(url))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(putRequestedFor(urlMatching(url))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -2281,9 +2253,9 @@ public void testSetBroadcastLayoutWithScreenshareType() throws OpenTokException String expectedJson = "{\"type\":\"bestFit\",\"screenshareType\":\"pip\"}"; sdk.setBroadcastLayout(broadcastId, properties); verify(putRequestedFor(urlMatching(url)).withRequestBody(equalToJson(expectedJson))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(putRequestedFor(urlMatching(url))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -2379,9 +2351,9 @@ public void testSipDial() throws OpenTokException { assertNotNull(sip.getConnectionId()); assertNotNull(sip.getStreamId()); verify(postRequestedFor(urlMatching(url))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(url))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -2396,9 +2368,9 @@ public void testPlayDtmfAll() throws OpenTokException { sdk.playDTMF(sessionId, dtmfString); verify(postRequestedFor(urlMatching(path))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(deleteRequestedFor(urlMatching(path))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -2415,9 +2387,9 @@ public void testPlayDtmfSingle() throws OpenTokException { sdk.playDTMF(sessionId, connectionId, dtmfString); verify(postRequestedFor(urlMatching(path))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(deleteRequestedFor(urlMatching(path))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -2431,9 +2403,9 @@ public void testForceDisconnect() throws OpenTokException { .withHeader("Content-Type", "application/json"))); sdk.forceDisconnect(sessionId, connectionId); verify(deleteRequestedFor(urlMatching(path))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(deleteRequestedFor(urlMatching(path))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); assertThrows(InvalidArgumentException.class, () -> sdk.forceDisconnect("", connectionId)); assertThrows(InvalidArgumentException.class, () -> sdk.forceDisconnect(sessionId, "")); } @@ -2471,7 +2443,7 @@ public void testCreateSessionWithProxy() throws OpenTokException, UnknownHostExc verify(postRequestedFor(urlMatching(SESSION_CREATE))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(SESSION_CREATE))))); } @@ -2520,9 +2492,9 @@ public void testStartRender() throws Exception { assertNull(render.getReason()); verify(postRequestedFor(urlMatching(url))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(url))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); assertThrows(InvalidArgumentException.class, () -> sdk.startRender("", token, properties)); } @@ -2564,9 +2536,9 @@ public void testGetRender() throws Exception { assertNull(render.getStreamId()); verify(getRequestedFor(urlMatching(url))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(getRequestedFor(urlMatching(url))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -2578,9 +2550,9 @@ public void testStopRender() throws Exception { sdk.stopRender(renderId); verify(deleteRequestedFor(urlMatching(url))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(deleteRequestedFor(urlMatching(url))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -2648,9 +2620,9 @@ public void testListRenders() throws Exception { assertNull(render.getReason()); verify(getRequestedFor(urlMatching(endpoint))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(getRequestedFor(urlMatching(endpoint))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); } @Test @@ -2837,9 +2809,9 @@ public void testStartCaptions() throws Exception { assertTrue(caption.toString().contains(captionsId)); verify(postRequestedFor(urlMatching(url))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(postRequestedFor(urlMatching(url))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); assertThrows(InvalidArgumentException.class, () -> sdk.startCaptions("", token, properties)); assertThrows(InvalidArgumentException.class, () -> sdk.startCaptions(sessionId, "", properties)); @@ -2872,12 +2844,54 @@ public void testStopCaptions() throws Exception { sdk.stopCaptions(captionsId); verify(postRequestedFor(urlMatching(url))); - assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret, + assertTrue(TestHelpers.verifyTokenAuth(apiKey, apiSecret, findAll(deleteRequestedFor(urlMatching(url))))); - Helpers.verifyUserAgent(); + TestHelpers.verifyUserAgent(); assertThrows(InvalidArgumentException.class, () -> sdk.stopCaptions("")); stubFor(post(urlEqualTo(url)).willReturn(aResponse().withStatus(404))); assertThrows(RequestException.class, () -> sdk.stopCaptions(captionsId)); } + + @Test + public void testVonageShim() throws Exception { + String appId = UUID.randomUUID().toString(); + String testResourceDir = Paths.get(getClass().getResource("").toURI()).toString() + .replace("classes\\java", "classes/java") + .replace("classes/java", "resources"); + var privateKeyPath = Paths.get(testResourceDir, "application_key"); + OpenTok vonage = new OpenTok(appId, privateKeyPath); + assertNotNull(vonage); + assertEquals("https://video.api.vonage.com", vonage.client.getApiUrl()); + + String data = "{\"key\":\"value\", \"F00B4R\": true}"; + String token = vonage.generateToken(sessionId, new TokenOptions.Builder() + .role(Role.PUBLISHER_ONLY).data(data) + .initialLayoutClassList(List.of("focus")) + .build() + ); + assertNotNull(token); + var publicKeyPath = Paths.get(testResourceDir, "application_public_key.der"); + var spec = new X509EncodedKeySpec(Files.readAllBytes(publicKeyPath)); + var key = KeyFactory.getInstance("RSA").generatePublic(spec); + var claims = Jwts.parser().verifyWith(key).build().parseSignedClaims(token).getPayload(); + + assertNotNull(claims); + assertEquals(appId, claims.get("application_id")); + assertEquals(sessionId, claims.get("session_id")); + assertNotNull(claims.get("nonce")); + assertNotNull(claims.get("jti")); + assertEquals("publisheronly", claims.get("role")); + assertEquals("session.connect", claims.get("scope")); + assertEquals(data, claims.get("connection_data")); + assertEquals("focus", claims.get("initial_layout_class_list")); + + var exp = claims.getExpiration().toInstant(); + var iat = claims.getIssuedAt().toInstant(); + assertTrue(iat.isAfter(Instant.now().minus(1, ChronoUnit.MINUTES))); + assertTrue(iat.isBefore(Instant.now().plus(1, ChronoUnit.MINUTES))); + assertTrue(exp.isAfter(iat)); + assertTrue(iat.plus(86402, ChronoUnit.SECONDS).isAfter(exp)); + assertTrue(iat.plus(86398, ChronoUnit.SECONDS).isBefore(exp)); + } } \ No newline at end of file diff --git a/src/test/java/com/opentok/test/Helpers.java b/src/test/java/com/opentok/TestHelpers.java similarity index 96% rename from src/test/java/com/opentok/test/Helpers.java rename to src/test/java/com/opentok/TestHelpers.java index a7690c3..774f01b 100644 --- a/src/test/java/com/opentok/test/Helpers.java +++ b/src/test/java/com/opentok/TestHelpers.java @@ -5,7 +5,7 @@ * * Licensed under The MIT License (MIT). See LICENSE file for more information. */ -package com.opentok.test; +package com.opentok; import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder; import com.github.tomakehurst.wiremock.http.Request; @@ -34,7 +34,7 @@ import static com.opentok.util.Crypto.signData; import static com.opentok.util.TokenGenerator.*; -public class Helpers { +public class TestHelpers { public static final String JTI = "jti"; @@ -62,7 +62,8 @@ public static boolean verifyTokenSignature(String token, String apiSecret) throw public static boolean verifyTokenAuth(Integer apiKey, String apiSecret, List requests) { for (Request request: requests) { - if (!verifyJWTClaims(request.getHeader("X-OPENTOK-AUTH"), apiKey, apiSecret)) { + String token = request.getHeader("X-OPENTOK-AUTH"); + if (!verifyJWTClaims(token, apiKey, apiSecret)) { return false; } } @@ -123,5 +124,4 @@ public static boolean verifyJWTClaims(String token, Integer apiKey, String apiSe return false; } } - } diff --git a/src/test/resources/com/opentok/application_key b/src/test/resources/com/opentok/application_key new file mode 100644 index 0000000..4b654b2 --- /dev/null +++ b/src/test/resources/com/opentok/application_key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDqSe/genQY2KUz +xc1iqj2pgeH1k2SKHpIK8L8JLwfEEskhG92Ch9euivu30roKHTVMI4lXRrOL0OyM +uX0EZQGSuDvB8cZpOL+044oV3XInx/LwkEgHIsB7anv6rJ/fyxHTGvlc1c3DmQhl +J5ToFtu2DL8dY/nmYvdpeo74+0iOyTODiGCNrB8Kqc7zrx/KQM732BBrLeRs6TwY ++7lQYIebFQN5C9JvGWAlStw9IJO+dlJojMru9bz//B+rWe350m5WiVSFHnSP5K6o +t1SBuraoJRsdORwVb9dp0gU3UDkGApYgmBFTt0MJoCZWNA3QNkJ8clpjh8JJtIcF +dWFL2mvxAgMBAAECggEAZZd9/rbalNOMfzCsaLYtWs1JL/WjyQiMh1XxYIgWM/15 +XXP5z1ocOkFl+UXVCgG0VLmsGj48KMqFaFgeT8OEtRxSPT0brhC/gC6Sd/y4PWvE +em/167I0CNAZxo8IHECwD/xIWOsU+FXpgANz3FfdGcnZLWNmv3H2mrRcPrantdHQ +oMiS2wCF+6Zyo0TTVdddHjvQAutznMEoQLdTvl3MtGY5WWchDzFAmwqDv/+ne9H7 +aerpq3tv1Ng0uOfzw39UuUTqrYXrqYDGYtK2D5yoEzN6ktK2uYIV0MIf9Eh5FRp9 +YoYYI7t/3SHXwidViOE8wXVhZ0DUbyIbYv97elebyQKBgQD7KrXFmMBYcxVJsEx0 +QQFRUu9iRkqMrfsINc/O79y81oD8ewc2snizyubdrRv0CCz3wFVlCBRwCURiczpC +il+EsrbIhdVyQZVRGCUNDDwMP7T/r7mBFqVyQfSgIFGKkexkCUnxW7pxZjkpBiWA +HnAvKrzTor5AEE/Wn3t7VRWAjwKBgQDuzBVApH/0Y52wQPU/t8drJQSDkFzhA3ov +CsIUvLXsS5ZfK2p4jBZzWG9IpJABkNWjsqnFqEeo9GlHtDeNyORl7pz7yYSPy+/X +eD0o+MIkJf8EnaVIVRn/zcy0d8uFBM0UTNsLwWZrMHnhjId8FxMwwJU7i6K4sGzT +9BWfLX6LfwKBgEY7vTSR8EdLdwpyCA8CFnI9NL9QVIxeIjI7ie6d2CXd/Zecd3nu +Eh6EgGZAf+6PUrO8zqQ/zCdAECVPf10YAHnE16Pe+L7IZA6XJ9UsNKZgMibFZqQY +Rw9aLiOQpfyPrYCTsF+TfOE06or0MwxOdqRZ2Q99FKIpbYngctEcC7U1AoGBAIn2 +IGUrZL1l/AmDTe2VGMJfLZ9w/SgG4UViWsSuThCJjwPGyomArcvQEOMQKB6vda5Q +n2MRmO0U3+pMRThGEyaM1+dkApEtSpDa58LPDSLjTNV22rHScOXoGVc+Sre8EVuk +F31QLALLi+7ySKg5kJ2+9bjkMIuxaf5+ayt+ljizAoGAc67guCr7ORjvPggGfn2U +xeYuo+nUvoXtsNkkIFzLx10FGuKI9kqi3+QFB25v4VC4eVTQNDDh7/wSSgGckWWI +YCxTjcvkq64pLstLref++RMBE6zK/gPsWJvuYg7xKLMsgyzm4kjk6ewDwzQkl2Be +uABeedOm0bI4QRVo4jDKs3c= +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/src/test/resources/com/opentok/application_public_key.der b/src/test/resources/com/opentok/application_public_key.der new file mode 100644 index 0000000..c3ca96f Binary files /dev/null and b/src/test/resources/com/opentok/application_public_key.der differ