From cd588dce5c225d6e661192c31daee937a17f5b67 Mon Sep 17 00:00:00 2001 From: Alex Laird Date: Mon, 8 Apr 2024 09:30:14 -0500 Subject: [PATCH] Prep for 2.3.0 release (#96) * Implemented UserAgentFilter and Policy on CreateTunnel and from config. Rename TunnelIPRestrictions classes (bug), not plural in ngrok docs. Add us-cal-1 region. Ensure list in Builders are immutable. Minor documentation updates. --- .github/workflows/build.yml | 1 + .github/workflows/nightly.yml | 1 + .github/workflows/validate.yml | 1 + CHANGELOG.md | 13 +- build.gradle | 2 +- .../ngrok/protocol/CreateTunnel.java | 137 ++++++++--- .../alexdlaird/ngrok/protocol/Region.java | 2 + .../ngrok/protocol/TunnelHeader.java | 21 +- .../ngrok/protocol/TunnelIPRestriction.java | 95 ++++++++ .../ngrok/protocol/TunnelIPRestrictions.java | 90 -------- .../ngrok/protocol/TunnelOAuth.java | 39 ++-- .../ngrok/protocol/TunnelPolicy.java | 116 ++++++++++ .../ngrok/protocol/TunnelPolicyActions.java | 90 ++++++++ .../ngrok/protocol/TunnelUserAgentFilter.java | 95 ++++++++ .../ngrok/protocol/TunnelVerifyWebhook.java | 12 +- .../ngrok/protocol/CreateTunnelTest.java | 216 +++++++++++------- 16 files changed, 698 insertions(+), 233 deletions(-) create mode 100644 src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelIPRestriction.java delete mode 100644 src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelIPRestrictions.java create mode 100644 src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelPolicy.java create mode 100644 src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelPolicyActions.java create mode 100644 src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelUserAgentFilter.java diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e38d4e03..5041c0f0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,6 +16,7 @@ jobs: env: NGROK_AUTHTOKEN: ${{ secrets.NGROK_AUTHTOKEN }} + NGROK_DOMAIN: ${{ secrets.NGROK_DOMAIN }} NGROK_HTTP_EDGE: ${{ secrets.NGROK_HTTP_EDGE }} NGROK_TCP_EDGE: ${{ secrets.NGROK_TCP_EDGE }} NGROK_API_KEY: ${{ secrets.NGROK_API_KEY }} diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 56246c6e..84464d1d 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -10,6 +10,7 @@ jobs: env: NGROK_AUTHTOKEN: ${{ secrets.NGROK_AUTHTOKEN }} + NGROK_DOMAIN: ${{ secrets.NGROK_DOMAIN }} NGROK_HTTP_EDGE: ${{ secrets.NGROK_HTTP_EDGE }} NGROK_TCP_EDGE: ${{ secrets.NGROK_TCP_EDGE }} NGROK_API_KEY: ${{ secrets.NGROK_API_KEY }} diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 32631bae..4a5288fa 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -9,6 +9,7 @@ jobs: env: NGROK_AUTHTOKEN: ${{ secrets.NGROK_AUTHTOKEN }} + NGROK_DOMAIN: ${{ secrets.NGROK_DOMAIN }} NGROK_HTTP_EDGE: ${{ secrets.NGROK_HTTP_EDGE }} NGROK_TCP_EDGE: ${{ secrets.NGROK_TCP_EDGE }} NGROK_API_KEY: ${{ secrets.NGROK_API_KEY }} diff --git a/CHANGELOG.md b/CHANGELOG.md index e819a7a8..f09242b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,10 +3,19 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased](https://github.com/alexdlaird/java-ngrok/compare/2.2.16...HEAD) +## [Unreleased](https://github.com/alexdlaird/java-ngrok/compare/2.3.0...HEAD) + +## [2.3.0](https://github.com/alexdlaird/java-ngrok/compare/2.2.16...2.3.0) - 2024-04-08 ### Added -- Support for `domain ` configuration when building [CreateTunnel](https://javadoc.io/static/com.github.alexdlaird/java-ngrok/2.2.17/com.github.alexdlaird.ngrok/com/github/alexdlaird/ngrok/protocol/CreateTunnel.Builder.html#withDomain(java.lang.String)). +- Support for `domain ` configuration when building [CreateTunnel](https://javadoc.io/static/com.github.alexdlaird/java-ngrok/2.3.0/com.github.alexdlaird.ngrok/com/github/alexdlaird/ngrok/protocol/CreateTunnel.Builder.html#withDomain(java.lang.String)). +- Support for `user_agent_filter ` configuration when building [CreateTunnel](https://javadoc.io/static/com.github.alexdlaird/java-ngrok/2.3.0/com.github.alexdlaird.ngrok/com/github/alexdlaird/ngrok/protocol/CreateTunnel.Builder.html#withUserAgentFilter(com.github.alexdlaird.ngrok.protocol.TunnelUserAgentFilter)). +- Support for `policy ` configuration when building [CreateTunnel](https://javadoc.io/static/com.github.alexdlaird/java-ngrok/2.3.0/com.github.alexdlaird.ngrok/com/github/alexdlaird/ngrok/protocol/CreateTunnel.Builder.html#withPolicy(com.github.alexdlaird.ngrok.protocol.TunnelPolicy)). +- `us-cal-1` to [Region](https://javadoc.io/doc/com.github.alexdlaird/java-ngrok/2.3.0/com.github.alexdlaird.ngrok/com/github/alexdlaird/ngrok/protocol/Region.html). - Test cases for TLS tunnels. +- Build improvements. + +### Fixed +- `ngrok` config value `ip_restriction` was incorrectly plural in previous versions of `java-ngrok`. Value is now interpreted as singular to align with [the `ngrok` docs](https://ngrok.com/docs/agent/config/#http-configuration), and classes and methods associated with it, like [TunnelIPRestriction](https://javadoc.io/doc/com.github.alexdlaird/java-ngrok/2.3.0/com.github.alexdlaird.ngrok/com/github/alexdlaird/ngrok/protocol/TunnelIPRestriction.html), have been renamed. ## [2.2.16](https://github.com/alexdlaird/java-ngrok/compare/2.2.15...2.2.16) - 2024-03-24 ### Added diff --git a/build.gradle b/build.gradle index 3cc7f462..311fc734 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,7 @@ plugins { } group "com.github.alexdlaird" -version "2.2.16" +version "2.3.0" java { withJavadocJar() diff --git a/src/main/java/com/github/alexdlaird/ngrok/protocol/CreateTunnel.java b/src/main/java/com/github/alexdlaird/ngrok/protocol/CreateTunnel.java index 7753c6d8..a33f3552 100644 --- a/src/main/java/com/github/alexdlaird/ngrok/protocol/CreateTunnel.java +++ b/src/main/java/com/github/alexdlaird/ngrok/protocol/CreateTunnel.java @@ -13,6 +13,7 @@ import com.github.alexdlaird.ngrok.NgrokClient; import com.github.alexdlaird.ngrok.conf.JavaNgrokConfig; import com.github.alexdlaird.ngrok.installer.NgrokVersion; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.UUID; @@ -71,8 +72,11 @@ public class CreateTunnel { private final String terminateAt; private final TunnelHeader requestHeader; private final TunnelHeader responseHeader; - private final TunnelIPRestrictions ipRestrictions; + private final TunnelIPRestriction ipRestriction; private final TunnelVerifyWebhook verifyWebhook; + private final TunnelUserAgentFilter userAgentFilter; + private final TunnelPolicy policyInbound; + private final TunnelPolicy policyOutbound; private final List labels; private CreateTunnel(final Builder builder) { @@ -103,8 +107,11 @@ private CreateTunnel(final Builder builder) { this.terminateAt = builder.terminateAt; this.requestHeader = builder.requestHeader; this.responseHeader = builder.responseHeader; - this.ipRestrictions = builder.ipRestrictions; + this.ipRestriction = builder.ipRestriction; this.verifyWebhook = builder.verifyWebhook; + this.userAgentFilter = builder.userAgentFilter; + this.policyInbound = builder.policyInbound; + this.policyOutbound = builder.policyOutbound; this.labels = builder.labels; } @@ -301,8 +308,8 @@ public TunnelHeader getResponseHeader() { /** * Get the IP restrictions for the tunnel. */ - public TunnelIPRestrictions getIpRestrictions() { - return ipRestrictions; + public TunnelIPRestriction getIpRestriction() { + return ipRestriction; } /** @@ -313,7 +320,29 @@ public TunnelVerifyWebhook getVerifyWebhook() { } /** - * Get the labels. + * Get the UserAgent filters. + */ + public TunnelUserAgentFilter getUserAgentFilter() { + return userAgentFilter; + } + + /** + * Get the inbound policy. + */ + public TunnelPolicy getPolicyInbound() { + return policyInbound; + } + + /** + * Get the outbound policy. + */ + public TunnelPolicy getPolicyOutbound() { + return policyOutbound; + } + + /** + * Get the labels. Note that labels can only be provisioned from the ngrok config file and not the + * Builder. */ public List getLabels() { return labels; @@ -355,8 +384,11 @@ public static class Builder { private String terminateAt; private TunnelHeader requestHeader; private TunnelHeader responseHeader; - private TunnelIPRestrictions ipRestrictions; + private TunnelIPRestriction ipRestriction; private TunnelVerifyWebhook verifyWebhook; + private TunnelUserAgentFilter userAgentFilter; + private TunnelPolicy policyInbound; + private TunnelPolicy policyOutbound; private List labels; /** @@ -415,8 +447,11 @@ public Builder(final CreateTunnel createTunnel) { this.terminateAt = createTunnel.terminateAt; this.requestHeader = createTunnel.requestHeader; this.responseHeader = createTunnel.responseHeader; - this.ipRestrictions = createTunnel.ipRestrictions; + this.ipRestriction = createTunnel.ipRestriction; this.verifyWebhook = createTunnel.verifyWebhook; + this.userAgentFilter = createTunnel.userAgentFilter; + this.policyInbound = createTunnel.policyInbound; + this.policyOutbound = createTunnel.policyOutbound; } /** @@ -587,7 +622,7 @@ public Builder withSchemes(final List schemes) { throw new IllegalArgumentException("Cannot set both 'schemes' and 'bindTls'."); } - this.schemes = schemes; + this.schemes = Collections.unmodifiableList(schemes); return this; } @@ -601,14 +636,14 @@ public Builder withBasicAuth(final List basicAuth) { throw new IllegalArgumentException("Cannot set both 'auth' and 'basicAuth'."); } - this.basicAuth = basicAuth; + this.basicAuth = Collections.unmodifiableList(basicAuth); return this; } /** * Set of OAuth settings to enable OAuth authentication on the tunnel endpoint. */ - public Builder withOAuth(TunnelOAuth oauth) { + public Builder withOAuth(final TunnelOAuth oauth) { this.oauth = oauth; return this; } @@ -616,7 +651,7 @@ public Builder withOAuth(TunnelOAuth oauth) { /** * The circuit breaker trigger. */ - public Builder withCircuitBreaker(Float circuitBreaker) { + public Builder withCircuitBreaker(final Float circuitBreaker) { this.circuitBreaker = circuitBreaker; return this; } @@ -624,7 +659,7 @@ public Builder withCircuitBreaker(Float circuitBreaker) { /** * Whether compression is enabled on this tunnel. */ - public Builder withCompression(Boolean compression) { + public Builder withCompression(final Boolean compression) { this.compression = compression; return this; } @@ -632,7 +667,7 @@ public Builder withCompression(Boolean compression) { /** * The path to the TLS certificate authority to verify client certs. */ - public Builder withMutualTlsCas(String mutualTlsCas) { + public Builder withMutualTlsCas(final String mutualTlsCas) { this.mutualTlsCas = mutualTlsCas; return this; } @@ -640,7 +675,7 @@ public Builder withMutualTlsCas(String mutualTlsCas) { /** * The proxy proto. */ - public Builder withProxyProto(String proxyProto) { + public Builder withProxyProto(final String proxyProto) { this.proxyProto = proxyProto; return this; } @@ -648,7 +683,7 @@ public Builder withProxyProto(String proxyProto) { /** * Whether ingress connections are converted to TCP upstream. */ - public Builder withWebsocketTcpConverter(Boolean websocketTcpConverter) { + public Builder withWebsocketTcpConverter(final Boolean websocketTcpConverter) { this.websocketTcpConverter = websocketTcpConverter; return this; } @@ -656,7 +691,7 @@ public Builder withWebsocketTcpConverter(Boolean websocketTcpConverter) { /** * The termination point. */ - public Builder withTerminateAt(String terminateAt) { + public Builder withTerminateAt(final String terminateAt) { this.terminateAt = terminateAt; return this; } @@ -664,7 +699,7 @@ public Builder withTerminateAt(String terminateAt) { /** * The Headers to be added or removed from requests. */ - public Builder withRequestHeader(TunnelHeader requestHeader) { + public Builder withRequestHeader(final TunnelHeader requestHeader) { this.requestHeader = requestHeader; return this; } @@ -672,7 +707,7 @@ public Builder withRequestHeader(TunnelHeader requestHeader) { /** * The Headers to be added or removed from responses. */ - public Builder withResponseHeader(TunnelHeader responseHeader) { + public Builder withResponseHeader(final TunnelHeader responseHeader) { this.responseHeader = responseHeader; return this; } @@ -680,19 +715,43 @@ public Builder withResponseHeader(TunnelHeader responseHeader) { /** * The IP restrictions for the tunnel. */ - public Builder withIpRestrictions(TunnelIPRestrictions ipRestrictions) { - this.ipRestrictions = ipRestrictions; + public Builder withIpRestriction(final TunnelIPRestriction ipRestriction) { + this.ipRestriction = ipRestriction; return this; } /** * The signature for webhooks. */ - public Builder withVerifyWebhook(TunnelVerifyWebhook verifyWebhook) { + public Builder withVerifyWebhook(final TunnelVerifyWebhook verifyWebhook) { this.verifyWebhook = verifyWebhook; return this; } + /** + * The UserAgent filter for the tunnel. + */ + public Builder withUserAgentFilter(final TunnelUserAgentFilter userAgentFilter) { + this.userAgentFilter = userAgentFilter; + return this; + } + + /** + * The inbound policy for the tunnel. + */ + public Builder withPolicyInbound(final TunnelPolicy policyInbound) { + this.policyInbound = policyInbound; + return this; + } + + /** + * The outbound policy for the tunnel. + */ + public Builder withPolicyOutbound(final TunnelPolicy policyOutbound) { + this.policyOutbound = policyOutbound; + return this; + } + /** * Populate any null attributes (except for name) in this Builder with values from * the given tunnelDefinition. @@ -744,10 +803,14 @@ public Builder withTunnelDefinition(Map tunnelDefinition) { this.metadata = (String) tunnelDefinition.get("metadata"); } if (isNull(this.schemes) && tunnelDefinition.containsKey("schemes")) { - this.schemes = (List) tunnelDefinition.get("schemes"); + this.schemes = Collections.unmodifiableList( + (List) tunnelDefinition.get("schemes") + ); } if (isNull(this.basicAuth) && tunnelDefinition.containsKey("basic_auth")) { - this.basicAuth = (List) tunnelDefinition.get("basic_auth"); + this.basicAuth = Collections.unmodifiableList( + (List) tunnelDefinition.get("basic_auth") + ); } if (isNull(this.oauth) && tunnelDefinition.containsKey("oauth")) { this.oauth = new TunnelOAuth.Builder((Map) tunnelDefinition.get("oauth")).build(); @@ -782,9 +845,9 @@ public Builder withTunnelDefinition(Map tunnelDefinition) { .Builder((Map) tunnelDefinition.get("response_header")) .build(); } - if (isNull(this.ipRestrictions) && tunnelDefinition.containsKey("ip_restrictions")) { - this.ipRestrictions = new TunnelIPRestrictions - .Builder((Map) tunnelDefinition.get("ip_restrictions")) + if (isNull(this.ipRestriction) && tunnelDefinition.containsKey("ip_restriction")) { + this.ipRestriction = new TunnelIPRestriction + .Builder((Map) tunnelDefinition.get("ip_restriction")) .build(); } if (isNull(this.verifyWebhook) && tunnelDefinition.containsKey("verify_webhook")) { @@ -792,12 +855,32 @@ public Builder withTunnelDefinition(Map tunnelDefinition) { .Builder((Map) tunnelDefinition.get("verify_webhook")) .build(); } + if (isNull(this.userAgentFilter) && tunnelDefinition.containsKey("user_agent_filter")) { + this.userAgentFilter = new TunnelUserAgentFilter + .Builder((Map) tunnelDefinition.get("user_agent_filter")) + .build(); + } + if (tunnelDefinition.containsKey("policy")) { + final Map policy = (Map) tunnelDefinition.get("policy"); + if (isNull(this.policyInbound) && policy.containsKey("inbound")) { + this.policyInbound = new TunnelPolicy + .Builder((Map) policy.get("inbound")) + .build(); + } + if (isNull(this.policyOutbound) && policy.containsKey("outbound")) { + this.policyOutbound = new TunnelPolicy + .Builder((Map) policy.get("outbound")) + .build(); + } + } if (tunnelDefinition.containsKey("labels")) { if (nonNull(bindTls)) { throw new IllegalArgumentException("'bindTls' cannot be set when 'labels' is also on the " + "tunnel definition."); } - this.labels = (List) tunnelDefinition.get("labels"); + this.labels = Collections.unmodifiableList( + (List) tunnelDefinition.get("labels") + ); } // Returning this to allow chained configuration of diff --git a/src/main/java/com/github/alexdlaird/ngrok/protocol/Region.java b/src/main/java/com/github/alexdlaird/ngrok/protocol/Region.java index a58a985d..c0c6b7f4 100644 --- a/src/main/java/com/github/alexdlaird/ngrok/protocol/Region.java +++ b/src/main/java/com/github/alexdlaird/ngrok/protocol/Region.java @@ -16,6 +16,8 @@ public enum Region { @SerializedName("us") US, + @SerializedName("us-cal-1") + US_CAL_1, @SerializedName("eu") EU, @SerializedName("ap") diff --git a/src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelHeader.java b/src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelHeader.java index 377ad3a0..52de084c 100644 --- a/src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelHeader.java +++ b/src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelHeader.java @@ -6,6 +6,7 @@ package com.github.alexdlaird.ngrok.protocol; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -54,14 +55,18 @@ public Builder() { * Construct a TunnelHeader Builder from tunnel definition of request_header * or response_header. * - * @param tunnelHeaderDefinitions The map of Tunnel header attributes. + * @param tunnelHeaderDefinition The map of Tunnel header attributes. */ - public Builder(Map tunnelHeaderDefinitions) { - if (tunnelHeaderDefinitions.containsKey("add")) { - this.add = (List) tunnelHeaderDefinitions.get("add"); + public Builder(final Map tunnelHeaderDefinition) { + if (tunnelHeaderDefinition.containsKey("add")) { + this.add = Collections.unmodifiableList( + (List) tunnelHeaderDefinition.get("add") + ); } - if (tunnelHeaderDefinitions.containsKey("remove")) { - this.remove = (List) tunnelHeaderDefinitions.get("remove"); + if (tunnelHeaderDefinition.containsKey("remove")) { + this.remove = Collections.unmodifiableList( + (List) tunnelHeaderDefinition.get("remove") + ); } } @@ -69,7 +74,7 @@ public Builder(Map tunnelHeaderDefinitions) { * The list of headers to add. */ public TunnelHeader.Builder withAdd(final List add) { - this.add = add; + this.add = Collections.unmodifiableList(add); return this; } @@ -77,7 +82,7 @@ public TunnelHeader.Builder withAdd(final List add) { * The list of headers to remove. */ public TunnelHeader.Builder withRemove(final List remove) { - this.remove = remove; + this.remove = Collections.unmodifiableList(remove); return this; } diff --git a/src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelIPRestriction.java b/src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelIPRestriction.java new file mode 100644 index 00000000..9c91e388 --- /dev/null +++ b/src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelIPRestriction.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2021-2024 Alex Laird + * + * SPDX-License-Identifier: MIT + */ + +package com.github.alexdlaird.ngrok.protocol; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * An object that represents IP restriction for a {@link CreateTunnel}. + */ +public class TunnelIPRestriction { + + private final List allowCidrs; + private final List denyCidrs; + + private TunnelIPRestriction(final Builder builder) { + this.allowCidrs = builder.allowCidrs; + this.denyCidrs = builder.denyCidrs; + } + + /** + * Get the list of allowed CIDRs. + */ + public List getAllowCidrs() { + return allowCidrs; + } + + /** + * Get the list of denied CIDRs. + */ + public List getDenyCidrs() { + return denyCidrs; + } + + /** + * Builder for a {@link TunnelIPRestriction}. + */ + public static class Builder { + + private List allowCidrs; + private List denyCidrs; + + /** + * Construct a TunnelIPRestriction Builder. + */ + public Builder() { + } + + /** + * Construct a TunnelIPRestriction Builder from tunnel definition of ip_restriction. + * + * @param tunnelIPRestrictionDefinition The map of Tunnel IP restriction attributes. + */ + public Builder(final Map tunnelIPRestrictionDefinition) { + if (tunnelIPRestrictionDefinition.containsKey("allow_cidrs")) { + this.allowCidrs = Collections.unmodifiableList( + (List) tunnelIPRestrictionDefinition.get("allow_cidrs") + ); + } + if (tunnelIPRestrictionDefinition.containsKey("deny_cidrs")) { + this.denyCidrs = Collections.unmodifiableList( + (List) tunnelIPRestrictionDefinition.get("deny_cidrs") + ); + } + } + + /** + * The list of allowed CIDRs. + */ + public TunnelIPRestriction.Builder withAllowCidrs(final List allowCidrs) { + this.allowCidrs = Collections.unmodifiableList(allowCidrs); + return this; + } + + /** + * The list of denied CIDRs. + */ + public TunnelIPRestriction.Builder withDenyCidrs(final List denyCidrs) { + this.denyCidrs = Collections.unmodifiableList(denyCidrs); + return this; + } + + /** + * Build the {@link TunnelIPRestriction}. + */ + public TunnelIPRestriction build() { + return new TunnelIPRestriction(this); + } + } +} diff --git a/src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelIPRestrictions.java b/src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelIPRestrictions.java deleted file mode 100644 index 87fae53e..00000000 --- a/src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelIPRestrictions.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2021-2024 Alex Laird - * - * SPDX-License-Identifier: MIT - */ - -package com.github.alexdlaird.ngrok.protocol; - -import java.util.List; -import java.util.Map; - -/** - * An object that represents IP restrictions for a {@link CreateTunnel}. - */ -public class TunnelIPRestrictions { - - private final List allowCidrs; - private final List denyCidrs; - - private TunnelIPRestrictions(final Builder builder) { - this.allowCidrs = builder.allowCidrs; - this.denyCidrs = builder.denyCidrs; - } - - /** - * Get the list of allowed CIDRs. - */ - public List getAllowCidrs() { - return allowCidrs; - } - - /** - * Get the list of denied CIDRs. - */ - public List getDenyCidrs() { - return denyCidrs; - } - - /** - * Builder for a {@link TunnelIPRestrictions}. - */ - public static class Builder { - - private List allowCidrs; - private List denyCidrs; - - /** - * Construct a TunnelIPRestrictions Builder. - */ - public Builder() { - } - - /** - * Construct a TunnelIPRestrictions Builder from tunnel definition of ip_restrictions. - * - * @param tunnelIPRestrictionsDefinitions The map of Tunnel IP restrictions attributes. - */ - public Builder(Map tunnelIPRestrictionsDefinitions) { - if (tunnelIPRestrictionsDefinitions.containsKey("allow_cidrs")) { - this.allowCidrs = (List) tunnelIPRestrictionsDefinitions.get("allow_cidrs"); - } - if (tunnelIPRestrictionsDefinitions.containsKey("deny_cidrs")) { - this.denyCidrs = (List) tunnelIPRestrictionsDefinitions.get("deny_cidrs"); - } - } - - /** - * The list of allowed CIDRs. - */ - public TunnelIPRestrictions.Builder withAllowCidrs(final List allowCidrs) { - this.allowCidrs = allowCidrs; - return this; - } - - /** - * The list of denied CIDRs. - */ - public TunnelIPRestrictions.Builder withDenyCidrs(final List denyCidrs) { - this.denyCidrs = denyCidrs; - return this; - } - - /** - * Build the {@link TunnelIPRestrictions}. - */ - public TunnelIPRestrictions build() { - return new TunnelIPRestrictions(this); - } - } -} diff --git a/src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelOAuth.java b/src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelOAuth.java index 004ccadf..35e44f06 100644 --- a/src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelOAuth.java +++ b/src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelOAuth.java @@ -6,6 +6,7 @@ package com.github.alexdlaird.ngrok.protocol; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -55,9 +56,9 @@ public List getAllowDomains() { } /** - * Builder for OAuth configuration that conforms to - * ngrok's tunnel definition. - * See docs for that class for example usage. + * Builder for OAuth configuration that conforms to ngrok's tunnel definition. See docs for that class for example usage. */ public static class Builder { @@ -75,20 +76,26 @@ public Builder() { /** * Construct a TunnelOAuth Builder from tunnel definition of oauth. * - * @param tunnelOAuthDefinitions The map of Tunnel OAuth attributes. + * @param tunnelOAuthDefinition The map of Tunnel OAuth attributes. */ - public Builder(Map tunnelOAuthDefinitions) { - if (tunnelOAuthDefinitions.containsKey("provider")) { - this.provider = (String) tunnelOAuthDefinitions.get("provider"); + public Builder(final Map tunnelOAuthDefinition) { + if (tunnelOAuthDefinition.containsKey("provider")) { + this.provider = (String) tunnelOAuthDefinition.get("provider"); } - if (tunnelOAuthDefinitions.containsKey("scopes")) { - this.scopes = (List) tunnelOAuthDefinitions.get("scopes"); + if (tunnelOAuthDefinition.containsKey("scopes")) { + this.scopes = Collections.unmodifiableList( + (List) tunnelOAuthDefinition.get("scopes") + ); } - if (tunnelOAuthDefinitions.containsKey("allow_emails")) { - this.allowEmails = (List) tunnelOAuthDefinitions.get("allow_emails"); + if (tunnelOAuthDefinition.containsKey("allow_emails")) { + this.allowEmails = Collections.unmodifiableList( + (List) tunnelOAuthDefinition.get("allow_emails") + ); } - if (tunnelOAuthDefinitions.containsKey("allow_domains")) { - this.allowDomains = (List) tunnelOAuthDefinitions.get("allow_domains"); + if (tunnelOAuthDefinition.containsKey("allow_domains")) { + this.allowDomains = Collections.unmodifiableList( + (List) tunnelOAuthDefinition.get("allow_domains") + ); } } @@ -105,7 +112,7 @@ public Builder withProvider(final String provider) { * The list of OAuth scopes. */ public Builder withScopes(final List scopes) { - this.scopes = scopes; + this.scopes = Collections.unmodifiableList(scopes); return this; } @@ -113,7 +120,7 @@ public Builder withScopes(final List scopes) { * The list of allowed OAuth emails. */ public Builder withAllowEmails(final List emails) { - this.allowEmails = emails; + this.allowEmails = Collections.unmodifiableList(emails); return this; } @@ -121,7 +128,7 @@ public Builder withAllowEmails(final List emails) { * The list of allowed OAuth domains. */ public Builder withAllowDomains(final List domains) { - this.allowDomains = domains; + this.allowDomains = Collections.unmodifiableList(domains); return this; } diff --git a/src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelPolicy.java b/src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelPolicy.java new file mode 100644 index 00000000..c29e233b --- /dev/null +++ b/src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelPolicy.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2021-2024 Alex Laird + * + * SPDX-License-Identifier: MIT + */ + +package com.github.alexdlaird.ngrok.protocol; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * An object that represents policy configuration for a {@link CreateTunnel}. + */ +public class TunnelPolicy { + + private final String name; + private final List expressions; + private final TunnelPolicyActions actions; + + private TunnelPolicy(final Builder builder) { + this.name = builder.name; + this.expressions = builder.expressions; + this.actions = builder.actions; + } + + /** + * Get the policy name. + */ + public String getName() { + return name; + } + + /** + * Get the policy expressions. + */ + public List getExpressions() { + return expressions; + } + + /** + * Get the policy actions. + */ + public TunnelPolicyActions getActions() { + return actions; + } + + /** + * Builder for a {@link TunnelPolicy}. + */ + public static class Builder { + + private String name; + private List expressions; + private TunnelPolicyActions actions; + + /** + * Construct a TunnelPolicy Builder. + */ + public Builder() { + } + + /** + * Construct a TunnelPolicy Builder from tunnel definition of policy. + * + * @param tunnelPolicyDefinition The map of Tunnel policy attributes. + */ + public Builder(final Map tunnelPolicyDefinition) { + if (tunnelPolicyDefinition.containsKey("name")) { + this.name = (String) tunnelPolicyDefinition.get("name"); + } + if (tunnelPolicyDefinition.containsKey("expressions")) { + this.expressions = Collections.unmodifiableList( + (List) tunnelPolicyDefinition.get("expressions") + ); + } + if (tunnelPolicyDefinition.containsKey("actions")) { + this.actions = new TunnelPolicyActions + .Builder((Map) tunnelPolicyDefinition.get("actions")) + .build(); + } + } + + /** + * The policy name. + */ + public TunnelPolicy.Builder withName(final String name) { + this.name = name; + return this; + } + + /** + * The list of policy expressions. + */ + public TunnelPolicy.Builder withExpressions(final List expressions) { + this.expressions = Collections.unmodifiableList(expressions); + return this; + } + + /** + * The policy actions. + */ + public TunnelPolicy.Builder withActions(final TunnelPolicyActions actions) { + this.actions = actions; + return this; + } + + /** + * Build the {@link TunnelPolicy}. + */ + public TunnelPolicy build() { + return new TunnelPolicy(this); + } + } +} diff --git a/src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelPolicyActions.java b/src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelPolicyActions.java new file mode 100644 index 00000000..3cd861a2 --- /dev/null +++ b/src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelPolicyActions.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2021-2024 Alex Laird + * + * SPDX-License-Identifier: MIT + */ + +package com.github.alexdlaird.ngrok.protocol; + +import java.util.Map; + +/** + * An object that represents policy actions configuration for a {@link CreateTunnel}. + */ +public class TunnelPolicyActions { + + private final String type; + private final String config; + + private TunnelPolicyActions(final Builder builder) { + this.type = builder.type; + this.config = builder.config; + } + + /** + * Get the action type. + */ + public String getType() { + return type; + } + + /** + * Get the action config. + */ + public String getConfig() { + return config; + } + + /** + * Builder for a {@link TunnelPolicyActions}. + */ + public static class Builder { + + private String type; + private String config; + + /** + * Construct a TunnelPolicy Builder. + */ + public Builder() { + } + + /** + * Construct a TunnelPolicyActions Builder from tunnel definition of policy.inbound.actions or + * policy.outbound.actions. + * + * @param tunnelPolicyActionsDefinition The map of Tunnel policy action attributes. + */ + public Builder(final Map tunnelPolicyActionsDefinition) { + if (tunnelPolicyActionsDefinition.containsKey("type")) { + this.type = (String) tunnelPolicyActionsDefinition.get("type"); + } + if (tunnelPolicyActionsDefinition.containsKey("config")) { + this.config = (String) tunnelPolicyActionsDefinition.get("config"); + } + } + + /** + * The action type. + */ + public TunnelPolicyActions.Builder withType(final String type) { + this.type = type; + return this; + } + + /** + * The action config. + */ + public TunnelPolicyActions.Builder withConfig(final String config) { + this.config = config; + return this; + } + + /** + * Build the {@link TunnelPolicyActions}. + */ + public TunnelPolicyActions build() { + return new TunnelPolicyActions(this); + } + } +} diff --git a/src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelUserAgentFilter.java b/src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelUserAgentFilter.java new file mode 100644 index 00000000..8cd1a787 --- /dev/null +++ b/src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelUserAgentFilter.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2021-2024 Alex Laird + * + * SPDX-License-Identifier: MIT + */ + +package com.github.alexdlaird.ngrok.protocol; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * An object that represents UserAgent filter for a {@link CreateTunnel}. + */ +public class TunnelUserAgentFilter { + + private final List allow; + private final List deny; + + private TunnelUserAgentFilter(final Builder builder) { + this.allow = builder.allow; + this.deny = builder.deny; + } + + /** + * Get the list of allowed UserAgent filters. + */ + public List getAllow() { + return allow; + } + + /** + * Get the list of denied UserAgent filters. + */ + public List getDeny() { + return deny; + } + + /** + * Builder for a {@link TunnelUserAgentFilter}. + */ + public static class Builder { + + private List allow; + private List deny; + + /** + * Construct a UserAgentFilter Builder. + */ + public Builder() { + } + + /** + * Construct a UserAgentFilter Builder from tunnel definition of user_agent_filters. + * + * @param tunnelUserAgentFilterDefinition The map of UserAgent filter attributes. + */ + public Builder(final Map tunnelUserAgentFilterDefinition) { + if (tunnelUserAgentFilterDefinition.containsKey("allow")) { + this.allow = Collections.unmodifiableList( + (List) tunnelUserAgentFilterDefinition.get("allow") + ); + } + if (tunnelUserAgentFilterDefinition.containsKey("deny")) { + this.deny = Collections.unmodifiableList( + (List) tunnelUserAgentFilterDefinition.get("deny") + ); + } + } + + /** + * The list of allowed UserAgent filters. + */ + public TunnelUserAgentFilter.Builder withAllow(final List allow) { + this.allow = Collections.unmodifiableList(allow); + return this; + } + + /** + * The list of denied UserAgent filters. + */ + public TunnelUserAgentFilter.Builder withDeny(final List deny) { + this.deny = Collections.unmodifiableList(deny); + return this; + } + + /** + * Build the {@link TunnelUserAgentFilter}. + */ + public TunnelUserAgentFilter build() { + return new TunnelUserAgentFilter(this); + } + } +} diff --git a/src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelVerifyWebhook.java b/src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelVerifyWebhook.java index 63352f9c..13878ada 100644 --- a/src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelVerifyWebhook.java +++ b/src/main/java/com/github/alexdlaird/ngrok/protocol/TunnelVerifyWebhook.java @@ -53,14 +53,14 @@ public Builder() { /** * Construct a TunnelVerifyWebhook Builder from tunnel definition of verify_webhook. * - * @param tunnelVerifyWebhookDefinitions The map of Tunnel OAuth attributes. + * @param tunnelVerifyWebhookDefinition The map of Tunnel OAuth attributes. */ - public Builder(Map tunnelVerifyWebhookDefinitions) { - if (tunnelVerifyWebhookDefinitions.containsKey("provider")) { - this.provider = (String) tunnelVerifyWebhookDefinitions.get("provider"); + public Builder(final Map tunnelVerifyWebhookDefinition) { + if (tunnelVerifyWebhookDefinition.containsKey("provider")) { + this.provider = (String) tunnelVerifyWebhookDefinition.get("provider"); } - if (tunnelVerifyWebhookDefinitions.containsKey("secret")) { - this.secret = (String) tunnelVerifyWebhookDefinitions.get("secret"); + if (tunnelVerifyWebhookDefinition.containsKey("secret")) { + this.secret = (String) tunnelVerifyWebhookDefinition.get("secret"); } } diff --git a/src/test/java/com/github/alexdlaird/ngrok/protocol/CreateTunnelTest.java b/src/test/java/com/github/alexdlaird/ngrok/protocol/CreateTunnelTest.java index a3054502..f391190c 100644 --- a/src/test/java/com/github/alexdlaird/ngrok/protocol/CreateTunnelTest.java +++ b/src/test/java/com/github/alexdlaird/ngrok/protocol/CreateTunnelTest.java @@ -23,46 +23,61 @@ public class CreateTunnelTest { public void testCreateTunnelParams() { // WHEN final CreateTunnel createTunnel = new CreateTunnel.Builder() - .withNgrokVersion(NgrokVersion.V2) - .withName("name") - .withProto(Proto.TCP) - .withDomain("pyngrok.com") - .withAddr(5000) - .withoutInspect() - .withAuth("auth-token") - .withHostHeader("host-header") - .withBindTls(false) - .withSubdomain("subdomain") - .withHostname("hostname") - .withCrt("crt") - .withKey("key") - .withClientCas("clientCas") - .withRemoteAddr("remoteAddr") - .withMetadata("metadata") - .withOAuth(new TunnelOAuth.Builder().withProvider("testcase") - .withAllowDomains(List.of("one.domain", "two.domain")) - .withAllowEmails(List.of("one@email", "two@email")) - .withScopes(List.of("ascope", "bscope")) - .build()) - .withCircuitBreaker(0.5f) - .withCompression(false) - .withMutualTlsCas("mutualTlsCas") - .withProxyProto("proxyProto") - .withWebsocketTcpConverter(false) - .withTerminateAt("provider") - .withRequestHeader(new TunnelHeader.Builder().withAdd(List.of("req-addition")) - .withRemove(List.of("req-subtraction")) - .build()) - .withResponseHeader(new TunnelHeader.Builder().withAdd(List.of("res-addition")) - .withRemove(List.of("res-subtraction")) - .build()) - .withIpRestrictions(new TunnelIPRestrictions.Builder().withAllowCidrs(List.of("allowed")) - .withDenyCidrs(List.of("denied")) - .build()) - .withVerifyWebhook(new TunnelVerifyWebhook.Builder().withProvider("provider") - .withSecret("secret") - .build()) - .build(); + .withNgrokVersion(NgrokVersion.V2) + .withName("name") + .withProto(Proto.TCP) + .withDomain("pyngrok.com") + .withAddr(5000) + .withoutInspect() + .withAuth("auth-token") + .withHostHeader("host-header") + .withBindTls(false) + .withSubdomain("subdomain") + .withHostname("hostname") + .withCrt("crt") + .withKey("key") + .withClientCas("clientCas") + .withRemoteAddr("remoteAddr") + .withMetadata("metadata") + .withOAuth(new TunnelOAuth.Builder().withProvider("testcase") + .withAllowDomains(List.of("one.domain", "two.domain")) + .withAllowEmails(List.of("one@email", "two@email")) + .withScopes(List.of("ascope", "bscope")) + .build()) + .withCircuitBreaker(0.5f) + .withCompression(false) + .withMutualTlsCas("mutualTlsCas") + .withProxyProto("proxyProto") + .withWebsocketTcpConverter(false) + .withTerminateAt("provider") + .withRequestHeader(new TunnelHeader.Builder().withAdd(List.of("req-addition")) + .withRemove(List.of("req-subtraction")) + .build()) + .withResponseHeader(new TunnelHeader.Builder().withAdd(List.of("res-addition")) + .withRemove(List.of("res-subtraction")) + .build()) + .withIpRestriction(new TunnelIPRestriction.Builder().withAllowCidrs(List.of("allowed")) + .withDenyCidrs(List.of("denied")) + .build()) + .withVerifyWebhook(new TunnelVerifyWebhook.Builder().withProvider("provider") + .withSecret("secret") + .build()) + .withUserAgentFilter(new TunnelUserAgentFilter.Builder().withAllow(List.of("allow-user-agent")) + .withDeny(List.of("deny-user-agent")) + .build()) + .withPolicyInbound(new TunnelPolicy.Builder().withName("inbound-policy") + .withExpressions(List.of("inbound-policy-expression")) + .withActions(new TunnelPolicyActions.Builder().withType("inbound-policy-actions-type") + .withConfig("inbound-policy-actions-config") + .build()) + .build()) + .withPolicyOutbound(new TunnelPolicy.Builder().withName("outbound-policy") + .withExpressions(List.of("outbound-policy-expression")) + .withActions(new TunnelPolicyActions.Builder().withType("outbound-policy-actions-type") + .withConfig("outbound-policy-actions-config") + .build()) + .build()) + .build(); // THEN assertEquals(NgrokVersion.V2, createTunnel.getNgrokVersion()); @@ -95,10 +110,20 @@ public void testCreateTunnelParams() { assertTrue(createTunnel.getRequestHeader().getRemove().contains("req-subtraction")); assertTrue(createTunnel.getResponseHeader().getAdd().contains("res-addition")); assertTrue(createTunnel.getResponseHeader().getRemove().contains("res-subtraction")); - assertTrue(createTunnel.getIpRestrictions().getAllowCidrs().contains("allowed")); - assertTrue(createTunnel.getIpRestrictions().getDenyCidrs().contains("denied")); + assertTrue(createTunnel.getIpRestriction().getAllowCidrs().contains("allowed")); + assertTrue(createTunnel.getIpRestriction().getDenyCidrs().contains("denied")); assertEquals("provider", createTunnel.getVerifyWebhook().getProvider()); assertEquals("secret", createTunnel.getVerifyWebhook().getSecret()); + assertTrue(createTunnel.getUserAgentFilter().getAllow().contains("allow-user-agent")); + assertTrue(createTunnel.getUserAgentFilter().getDeny().contains("deny-user-agent")); + assertEquals("inbound-policy", createTunnel.getPolicyInbound().getName()); + assertTrue(createTunnel.getPolicyInbound().getExpressions().contains("inbound-policy-expression")); + assertEquals("inbound-policy-actions-type", createTunnel.getPolicyInbound().getActions().getType()); + assertEquals("inbound-policy-actions-config", createTunnel.getPolicyInbound().getActions().getConfig()); + assertEquals("outbound-policy", createTunnel.getPolicyOutbound().getName()); + assertTrue(createTunnel.getPolicyOutbound().getExpressions().contains("outbound-policy-expression")); + assertEquals("outbound-policy-actions-type", createTunnel.getPolicyOutbound().getActions().getType()); + assertEquals("outbound-policy-actions-config", createTunnel.getPolicyOutbound().getActions().getConfig()); assertNull(createTunnel.getSchemes()); } @@ -107,8 +132,8 @@ public void testCreateTunnelParams() { public void testCreateTunnelSchemes() { // WHEN final CreateTunnel createTunnel = new CreateTunnel.Builder() - .withSchemes(List.of("http", "https")) - .build(); + .withSchemes(List.of("http", "https")) + .build(); // THEN assertNull(createTunnel.getBindTls()); @@ -120,19 +145,19 @@ public void testCreateTunnelSchemes() { @Test public void testCreateTunnelBindTlsAndSchemesFails() { assertThrows(IllegalArgumentException.class, () -> new CreateTunnel.Builder() - .withBindTls(BindTls.TRUE) - .withSchemes(List.of("http", "https"))); + .withBindTls(BindTls.TRUE) + .withSchemes(List.of("http", "https"))); assertThrows(IllegalArgumentException.class, () -> new CreateTunnel.Builder() - .withSchemes(List.of("http", "https")) - .withBindTls(BindTls.TRUE)); + .withSchemes(List.of("http", "https")) + .withBindTls(BindTls.TRUE)); } @Test public void testCreateTunnelBasicAuth() { final CreateTunnel createTunnel = new CreateTunnel.Builder() - .withBasicAuth(List.of("token-1", "token-2")) - .build(); + .withBasicAuth(List.of("token-1", "token-2")) + .build(); assertEquals(2, createTunnel.getBasicAuth().size()); assertEquals("token-1", createTunnel.getBasicAuth().get(0)); @@ -142,49 +167,63 @@ public void testCreateTunnelBasicAuth() { @Test public void testCreateTunnelAuthAndBasicAuthFails() { assertThrows(IllegalArgumentException.class, () -> new CreateTunnel.Builder() - .withAuth("auth-token") - .withBasicAuth(List.of("auth-token"))); + .withAuth("auth-token") + .withBasicAuth(List.of("auth-token"))); assertThrows(IllegalArgumentException.class, () -> new CreateTunnel.Builder() - .withBasicAuth(List.of("auth-token")) - .withAuth("auth-token")); + .withBasicAuth(List.of("auth-token")) + .withAuth("auth-token")); } @Test public void testCreateBindTlsLabelsFails() { // WHEN assertThrows(IllegalArgumentException.class, () -> new CreateTunnel.Builder() - .withTunnelDefinition(Map.of("bind_tls", true, "labels", List.of("edge=some-edge-id")))); + .withTunnelDefinition(Map.of("bind_tls", true, "labels", List.of("edge=some-edge-id")))); } @Test public void testCreateWithTunnelDefinitions() { // WHEN final CreateTunnel createTunnel = new CreateTunnel.Builder() - .withTunnelDefinition(Map.ofEntries( - Map.entry("labels", List.of("edge=some-edge-id")), - Map.entry("auth", "auth-token"), - Map.entry("host_header", "host-header"), - Map.entry("hostname", "hostname"), - Map.entry("crt", "crt"), - Map.entry("key", "key"), - Map.entry("client_cas", "clientCas"), - Map.entry("remote_addr", "remoteAddr"), - Map.entry("metadata", "metadata"), - Map.entry("compression", "false"), - Map.entry("mutual_tls_cas", "mutualTlsCas"), - Map.entry("proxy_proto", "proxyProto"), - Map.entry("websocket_tcp_converter", "false"), - Map.entry("terminate_at", "provider"), - Map.entry("request_header", - Map.of("add", List.of("req-addition"), "remove", List.of("req-subtraction"))), - Map.entry("response_header", - Map.of("add", List.of("res-addition"), "remove", List.of("res-subtraction"))), - Map.entry("ip_restrictions", - Map.of("allow_cidrs", List.of("allowed"), "deny_cidrs", List.of("denied"))), - Map.entry("verify_webhook", - Map.of("provider", "provider", "secret", "secret")))) - .build(); + .withTunnelDefinition(Map.ofEntries( + Map.entry("labels", List.of("edge=some-edge-id")), + Map.entry("auth", "auth-token"), + Map.entry("host_header", "host-header"), + Map.entry("hostname", "hostname"), + Map.entry("crt", "crt"), + Map.entry("key", "key"), + Map.entry("client_cas", "clientCas"), + Map.entry("remote_addr", "remoteAddr"), + Map.entry("metadata", "metadata"), + Map.entry("compression", "false"), + Map.entry("mutual_tls_cas", "mutualTlsCas"), + Map.entry("proxy_proto", "proxyProto"), + Map.entry("websocket_tcp_converter", "false"), + Map.entry("domain", "pyngrok.com"), + Map.entry("terminate_at", "provider"), + Map.entry("request_header", + Map.of("add", List.of("req-addition"), "remove", List.of("req-subtraction"))), + Map.entry("response_header", + Map.of("add", List.of("res-addition"), "remove", List.of("res-subtraction"))), + Map.entry("ip_restriction", + Map.of("allow_cidrs", List.of("allowed"), "deny_cidrs", List.of("denied"))), + Map.entry("verify_webhook", + Map.of("provider", "provider", "secret", "secret")), + Map.entry("user_agent_filter", + Map.of("allow", List.of("allow-user-agent"), "deny", List.of("deny-user-agent"))), + Map.entry("policy", + Map.of("inbound", + Map.of("name", "inbound-policy", + "expressions", List.of("inbound-policy-expression"), + "actions", + Map.of("type", "inbound-policy-actions-type", "config", "inbound-policy-actions-config")), + "outbound", + Map.of("name", "outbound-policy", + "expressions", List.of("outbound-policy-expression"), + "actions", + Map.of("type", "outbound-policy-actions-type", "config", "outbound-policy-actions-config"))))) + ).build(); // THEN assertEquals(1, createTunnel.getLabels().size()); @@ -201,15 +240,26 @@ public void testCreateWithTunnelDefinitions() { assertEquals("mutualTlsCas", createTunnel.getMutualTlsCas()); assertEquals("proxyProto", createTunnel.getProxyProto()); assertFalse(createTunnel.isWebsocketTcpConverter()); + assertEquals("pyngrok.com", createTunnel.getDomain()); assertEquals("provider", createTunnel.getTerminateAt()); assertTrue(createTunnel.getRequestHeader().getAdd().contains("req-addition")); assertTrue(createTunnel.getRequestHeader().getRemove().contains("req-subtraction")); assertTrue(createTunnel.getResponseHeader().getAdd().contains("res-addition")); assertTrue(createTunnel.getResponseHeader().getRemove().contains("res-subtraction")); - assertTrue(createTunnel.getIpRestrictions().getAllowCidrs().contains("allowed")); - assertTrue(createTunnel.getIpRestrictions().getDenyCidrs().contains("denied")); + assertTrue(createTunnel.getIpRestriction().getAllowCidrs().contains("allowed")); + assertTrue(createTunnel.getIpRestriction().getDenyCidrs().contains("denied")); assertEquals("provider", createTunnel.getVerifyWebhook().getProvider()); assertEquals("secret", createTunnel.getVerifyWebhook().getSecret()); + assertTrue(createTunnel.getUserAgentFilter().getAllow().contains("allow-user-agent")); + assertTrue(createTunnel.getUserAgentFilter().getDeny().contains("deny-user-agent")); + assertEquals("inbound-policy", createTunnel.getPolicyInbound().getName()); + assertTrue(createTunnel.getPolicyInbound().getExpressions().contains("inbound-policy-expression")); + assertEquals("inbound-policy-actions-type", createTunnel.getPolicyInbound().getActions().getType()); + assertEquals("inbound-policy-actions-config", createTunnel.getPolicyInbound().getActions().getConfig()); + assertEquals("outbound-policy", createTunnel.getPolicyOutbound().getName()); + assertTrue(createTunnel.getPolicyOutbound().getExpressions().contains("outbound-policy-expression")); + assertEquals("outbound-policy-actions-type", createTunnel.getPolicyOutbound().getActions().getType()); + assertEquals("outbound-policy-actions-config", createTunnel.getPolicyOutbound().getActions().getConfig()); assertNull(createTunnel.getBindTls()); } @@ -218,8 +268,8 @@ public void testCreateWithTunnelDefinitions() { public void testCreateWithTunnelDefinitionBasicAuth() { // WHEN final CreateTunnel createTunnel = new CreateTunnel.Builder() - .withTunnelDefinition(Map.of("basic_auth", List.of("token-1", "token-2"))) - .build(); + .withTunnelDefinition(Map.of("basic_auth", List.of("token-1", "token-2"))) + .build(); // THEN assertEquals(2, createTunnel.getBasicAuth().size());