mirror of
				https://github.com/SquidDev-CC/CC-Tweaked
				synced 2025-10-31 05:33:00 +00:00 
			
		
		
		
	HTTP rules now allow filtering by port
This commit is contained in:
		| @@ -5,7 +5,7 @@ org.gradle.jvmargs=-Xmx1G | |||||||
| mod_version=1.92.0 | mod_version=1.92.0 | ||||||
|  |  | ||||||
| # Minecraft properties | # Minecraft properties | ||||||
| mc_version=1.16.3 | mc_version=1.16.2 | ||||||
| mappings_version=31 | mappings_version=31 | ||||||
|  |  | ||||||
| # Dependencies | # Dependencies | ||||||
|   | |||||||
							
								
								
									
										20
									
								
								patchwork.md
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								patchwork.md
									
									
									
									
									
								
							| @@ -53,3 +53,23 @@ Fix additional `-` in docs | |||||||
|  |  | ||||||
| Why isn't this automatically stripped! Bad squid. | Why isn't this automatically stripped! Bad squid. | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  | 275ca58a82c627128a145a8754cbe32568536bd9 | ||||||
|  | HTTP rules now allow filtering by port | ||||||
|  |  | ||||||
|  | The HTTP filtering system becomes even more complex! Though in this | ||||||
|  | case, it's pretty minimal, and definitely worth doing. | ||||||
|  |  | ||||||
|  | For instance, the following rule will allow connecting to localhost on | ||||||
|  | port :8080. | ||||||
|  |  | ||||||
|  |     [[http.rules]] | ||||||
|  |     host = "127.0.0.1" | ||||||
|  |     port = 8080 | ||||||
|  |     action = "allow" | ||||||
|  |  | ||||||
|  |     # Other rules as before. | ||||||
|  |  | ||||||
|  | Closes #540 | ||||||
|  | ``` | ||||||
| @@ -126,10 +126,10 @@ public final class ComputerCraft implements ModInitializer { | |||||||
|  |  | ||||||
|     public static List<AddressRule> buildHttpRulesFromConfig(String[] blacklist, String[] whitelist) { |     public static List<AddressRule> buildHttpRulesFromConfig(String[] blacklist, String[] whitelist) { | ||||||
|         return Stream.concat(Stream.of(blacklist) |         return Stream.concat(Stream.of(blacklist) | ||||||
|                         .map(x -> AddressRule.parse(x, Action.DENY.toPartial())) |                         .map( x -> AddressRule.parse( x, null, Action.DENY.toPartial())) | ||||||
|                         .filter(Objects::nonNull), |                         .filter(Objects::nonNull), | ||||||
|                 Stream.of(whitelist) |                 Stream.of(whitelist) | ||||||
|                         .map(x -> AddressRule.parse(x, Action.ALLOW.toPartial())) |                         .map( x -> AddressRule.parse( x, null, Action.ALLOW.toPartial())) | ||||||
|                         .filter(Objects::nonNull)) |                         .filter(Objects::nonNull)) | ||||||
|                 .collect(Collectors.toList()); |                 .collect(Collectors.toList()); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -21,14 +21,14 @@ public class CheckUrl extends Resource<CheckUrl> { | |||||||
|     private static final String EVENT = "http_check"; |     private static final String EVENT = "http_check"; | ||||||
|     private final IAPIEnvironment environment; |     private final IAPIEnvironment environment; | ||||||
|     private final String address; |     private final String address; | ||||||
|     private final String host; |     private final URI uri; | ||||||
|     private Future<?> future; |     private Future<?> future; | ||||||
|  |  | ||||||
|     public CheckUrl(ResourceGroup<CheckUrl> limiter, IAPIEnvironment environment, String address, URI uri) { |     public CheckUrl(ResourceGroup<CheckUrl> limiter, IAPIEnvironment environment, String address, URI uri) { | ||||||
|         super(limiter); |         super(limiter); | ||||||
|         this.environment = environment; |         this.environment = environment; | ||||||
|         this.address = address; |         this.address = address; | ||||||
|         this.host = uri.getHost(); |         this.uri = uri; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void run() { |     public void run() { | ||||||
| @@ -45,8 +45,9 @@ public class CheckUrl extends Resource<CheckUrl> { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         try { |         try { | ||||||
|             InetSocketAddress netAddress = NetworkUtils.getAddress(this.host, 80, false); |             boolean ssl = uri.getScheme().equalsIgnoreCase( "https" ); | ||||||
|             NetworkUtils.getOptions(this.host, netAddress); |             InetSocketAddress netAddress = NetworkUtils.getAddress( uri, ssl ); | ||||||
|  |             NetworkUtils.getOptions( uri.getHost(), netAddress ); | ||||||
|  |  | ||||||
|             if (this.tryClose()) { |             if (this.tryClose()) { | ||||||
|                 this.environment.queueEvent(EVENT, this.address, true); |                 this.environment.queueEvent(EVENT, this.address, true); | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ | |||||||
| package dan200.computercraft.core.apis.http; | package dan200.computercraft.core.apis.http; | ||||||
|  |  | ||||||
| import java.net.InetSocketAddress; | import java.net.InetSocketAddress; | ||||||
|  | import java.net.URI; | ||||||
| import java.security.KeyStore; | import java.security.KeyStore; | ||||||
| import java.util.concurrent.ExecutorService; | import java.util.concurrent.ExecutorService; | ||||||
| import java.util.concurrent.SynchronousQueue; | import java.util.concurrent.SynchronousQueue; | ||||||
| @@ -94,6 +95,21 @@ public final class NetworkUtils { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Create a {@link InetSocketAddress} from a {@link java.net.URI}. | ||||||
|  |      * | ||||||
|  |      * Note, this may require a DNS lookup, and so should not be executed on the main CC thread. | ||||||
|  |      * | ||||||
|  |      * @param uri The URI to fetch. | ||||||
|  |      * @param ssl Whether to connect with SSL. This is used to find the default port if not otherwise specified. | ||||||
|  |      * @return The resolved address. | ||||||
|  |      * @throws HTTPRequestException If the host is not malformed. | ||||||
|  |      */ | ||||||
|  |     public static InetSocketAddress getAddress( URI uri, boolean ssl ) throws HTTPRequestException | ||||||
|  |     { | ||||||
|  |         return getAddress( uri.getHost(), uri.getPort(), ssl ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Create a {@link InetSocketAddress} from the resolved {@code host} and port. |      * Create a {@link InetSocketAddress} from the resolved {@code host} and port. | ||||||
|      * |      * | ||||||
| @@ -125,7 +141,7 @@ public final class NetworkUtils { | |||||||
|      * @throws HTTPRequestException If the host is not permitted |      * @throws HTTPRequestException If the host is not permitted | ||||||
|      */ |      */ | ||||||
|     public static Options getOptions(String host, InetSocketAddress address) throws HTTPRequestException { |     public static Options getOptions(String host, InetSocketAddress address) throws HTTPRequestException { | ||||||
|         Options options = AddressRule.apply(ComputerCraft.httpRules, host, address.getAddress()); |         Options options = AddressRule.apply( ComputerCraft.httpRules, host, address ); | ||||||
|         if (options.action == Action.DENY) { |         if (options.action == Action.DENY) { | ||||||
|             throw new HTTPRequestException("Domain not permitted"); |             throw new HTTPRequestException("Domain not permitted"); | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ package dan200.computercraft.core.apis.http.options; | |||||||
|  |  | ||||||
| import java.net.Inet6Address; | import java.net.Inet6Address; | ||||||
| import java.net.InetAddress; | import java.net.InetAddress; | ||||||
|  | import java.net.InetSocketAddress; | ||||||
| import java.util.regex.Pattern; | import java.util.regex.Pattern; | ||||||
|  |  | ||||||
| import javax.annotation.Nonnull; | import javax.annotation.Nonnull; | ||||||
| @@ -26,15 +27,22 @@ public final class AddressRule { | |||||||
|     public static final int WEBSOCKET_MESSAGE = 128 * 1024; |     public static final int WEBSOCKET_MESSAGE = 128 * 1024; | ||||||
|     private final HostRange ip; |     private final HostRange ip; | ||||||
|     private final Pattern domainPattern; |     private final Pattern domainPattern; | ||||||
|  |     private final Integer port; | ||||||
|     private final PartialOptions partial; |     private final PartialOptions partial; | ||||||
|     private AddressRule(@Nullable HostRange ip, @Nullable Pattern domainPattern, @Nonnull PartialOptions partial) { | 	private AddressRule( | ||||||
|  |         @Nullable HostRange ip, | ||||||
|  |         @Nullable Pattern domainPattern, | ||||||
|  |         @Nullable Integer port, | ||||||
|  |         @Nonnull PartialOptions partial ) | ||||||
|  | 	{ | ||||||
|         this.ip = ip; |         this.ip = ip; | ||||||
|         this.domainPattern = domainPattern; |         this.domainPattern = domainPattern; | ||||||
|         this.partial = partial; |         this.partial = partial; | ||||||
|  | 		this.port = port; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Nullable |     @Nullable | ||||||
|     public static AddressRule parse(String filter, @Nonnull PartialOptions partial) { |     public static AddressRule parse( String filter, @Nullable Integer port, @Nonnull PartialOptions partial ) { | ||||||
|         int cidr = filter.indexOf('/'); |         int cidr = filter.indexOf('/'); | ||||||
|         if (cidr >= 0) { |         if (cidr >= 0) { | ||||||
|             String addressStr = filter.substring(0, cidr); |             String addressStr = filter.substring(0, cidr); | ||||||
| @@ -73,14 +81,14 @@ public final class AddressRule { | |||||||
|                 size -= 8; |                 size -= 8; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             return new AddressRule(new HostRange(minBytes, maxBytes), null, partial); |             return new AddressRule(new HostRange(minBytes, maxBytes), null, port, partial); | ||||||
|         } else { |         } else { | ||||||
|             Pattern pattern = Pattern.compile("^\\Q" + filter.replaceAll("\\*", "\\\\E.*\\\\Q") + "\\E$"); |             Pattern pattern = Pattern.compile("^\\Q" + filter.replaceAll("\\*", "\\\\E.*\\\\Q") + "\\E$"); | ||||||
|             return new AddressRule(null, pattern, partial); |             return new AddressRule(null, pattern, port, partial); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static Options apply(Iterable<? extends AddressRule> rules, String domain, InetAddress address) { |     public static Options apply(Iterable<? extends AddressRule> rules, String domain, InetSocketAddress address) { | ||||||
|         PartialOptions options = null; |         PartialOptions options = null; | ||||||
|         boolean hasMany = false; |         boolean hasMany = false; | ||||||
|  |  | ||||||
| @@ -108,11 +116,14 @@ public final class AddressRule { | |||||||
|     /** |     /** | ||||||
|      * Determine whether the given address matches a series of patterns. |      * Determine whether the given address matches a series of patterns. | ||||||
|      * |      * | ||||||
|      * @param domain The domain to match |      * @param domain        The domain to match | ||||||
|      * @param address The address to check. |      * @param socketAddress The address to check. | ||||||
|      * @return Whether it matches any of these patterns. |      * @return Whether it matches any of these patterns. | ||||||
|      */ |      */ | ||||||
|     private boolean matches(String domain, InetAddress address) { |     private boolean matches(String domain, InetSocketAddress socketAddress) { | ||||||
|  | 		InetAddress address = socketAddress.getAddress(); | ||||||
|  |         if( port != null && port != socketAddress.getPort() ) return false; | ||||||
|  |  | ||||||
|         if (this.domainPattern != null) { |         if (this.domainPattern != null) { | ||||||
|             if (this.domainPattern.matcher(domain) |             if (this.domainPattern.matcher(domain) | ||||||
|                                   .matches()) { |                                   .matches()) { | ||||||
|   | |||||||
| @@ -9,6 +9,8 @@ package dan200.computercraft.core.apis.http.options; | |||||||
| public class AddressRuleConfig { | public class AddressRuleConfig { | ||||||
|     // TODO haha config is gone, do fix |     // TODO haha config is gone, do fix | ||||||
|  |  | ||||||
|  |     // TODO FIGURE OUT WHY THE HELL THE PREVIOUS GUY HAD TO COMMENT THIS OUT | ||||||
|  |  | ||||||
|     //    public static UnmodifiableConfig makeRule( String host, Action action ) |     //    public static UnmodifiableConfig makeRule( String host, Action action ) | ||||||
|     //    { |     //    { | ||||||
|     //        CommentedConfig config = InMemoryCommentedFormat.defaultInstance().createConfig( ConcurrentHashMap::new ); |     //        CommentedConfig config = InMemoryCommentedFormat.defaultInstance().createConfig( ConcurrentHashMap::new ); | ||||||
| @@ -39,17 +41,19 @@ public class AddressRuleConfig { | |||||||
|     //    { |     //    { | ||||||
|     //        String hostObj = get( builder, "host", String.class ).orElse( null ); |     //        String hostObj = get( builder, "host", String.class ).orElse( null ); | ||||||
|     //        return hostObj != null && checkEnum( builder, "action", Action.class ) |     //        return hostObj != null && checkEnum( builder, "action", Action.class ) | ||||||
|  |     //            && check( builder, "port", Number.class ) | ||||||
|     //            && check( builder, "timeout", Number.class ) |     //            && check( builder, "timeout", Number.class ) | ||||||
|     //            && check( builder, "max_upload", Number.class ) |     //            && check( builder, "max_upload", Number.class ) | ||||||
|     //            && check( builder, "max_download", Number.class ) |     //            && check( builder, "max_download", Number.class ) | ||||||
|     //            && check( builder, "websocket_message", Number.class ) |     //            && check( builder, "websocket_message", Number.class ) | ||||||
|     //            && AddressRule.parse( hostObj, PartialOptions.DEFAULT ) != null; |     //            && AddressRule.parse( hostObj, port, PartialOptions.DEFAULT ) != null; | ||||||
|     //    } |     //    } | ||||||
|     // |     // | ||||||
|     //    @Nullable |     //    @Nullable | ||||||
|     //    public static AddressRule parseRule( UnmodifiableConfig builder ) |     //    public static AddressRule parseRule( UnmodifiableConfig builder ) | ||||||
|     //    { |     //    { | ||||||
|     //        String hostObj = get( builder, "host", String.class ).orElse( null ); |     //        String hostObj = get( builder, "host", String.class ).orElse( null ); | ||||||
|  |     //        Integer port = get( builder, "port", Number.class ).map( Number::intValue ).orElse( null ); | ||||||
|     //        if( hostObj == null ) return null; |     //        if( hostObj == null ) return null; | ||||||
|     // |     // | ||||||
|     //        Action action = getEnum( builder, "action", Action.class ).orElse( null ); |     //        Action action = getEnum( builder, "action", Action.class ).orElse( null ); | ||||||
| @@ -66,7 +70,7 @@ public class AddressRuleConfig { | |||||||
|     //            websocketMessage |     //            websocketMessage | ||||||
|     //        ); |     //        ); | ||||||
|     // |     // | ||||||
|     //        return AddressRule.parse( hostObj, options ); |     //        return AddressRule.parse( hostObj, port, options ); | ||||||
|     //    } |     //    } | ||||||
|     // |     // | ||||||
|     //    private static <T> boolean check( UnmodifiableConfig config, String field, Class<T> klass ) |     //    private static <T> boolean check( UnmodifiableConfig config, String field, Class<T> klass ) | ||||||
|   | |||||||
| @@ -131,7 +131,7 @@ public class HttpRequest extends Resource<HttpRequest> { | |||||||
|         try { |         try { | ||||||
|             boolean ssl = uri.getScheme() |             boolean ssl = uri.getScheme() | ||||||
|                              .equalsIgnoreCase("https"); |                              .equalsIgnoreCase("https"); | ||||||
|             InetSocketAddress socketAddress = NetworkUtils.getAddress(uri.getHost(), uri.getPort(), ssl); |             InetSocketAddress socketAddress = NetworkUtils.getAddress(uri, ssl); | ||||||
|             Options options = NetworkUtils.getOptions(uri.getHost(), socketAddress); |             Options options = NetworkUtils.getOptions(uri.getHost(), socketAddress); | ||||||
|             SslContext sslContext = ssl ? NetworkUtils.getSslContext() : null; |             SslContext sslContext = ssl ? NetworkUtils.getSslContext() : null; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -117,7 +117,7 @@ public class Websocket extends Resource<Websocket> { | |||||||
|             boolean ssl = this.uri.getScheme() |             boolean ssl = this.uri.getScheme() | ||||||
|                                   .equalsIgnoreCase("wss"); |                                   .equalsIgnoreCase("wss"); | ||||||
|  |  | ||||||
|             InetSocketAddress socketAddress = NetworkUtils.getAddress(this.uri.getHost(), this.uri.getPort(), ssl); |             InetSocketAddress socketAddress = NetworkUtils.getAddress(uri, ssl); | ||||||
|             Options options = NetworkUtils.getOptions(this.uri.getHost(), socketAddress); |             Options options = NetworkUtils.getOptions(this.uri.getHost(), socketAddress); | ||||||
|             SslContext sslContext = ssl ? NetworkUtils.getSslContext() : null; |             SslContext sslContext = ssl ? NetworkUtils.getSslContext() : null; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -0,0 +1,34 @@ | |||||||
|  | /* | ||||||
|  |  * This file is part of ComputerCraft - http://www.computercraft.info | ||||||
|  |  * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. | ||||||
|  |  * Send enquiries to dratcliffe@gmail.com | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package dan200.computercraft.core.apis.http.options; | ||||||
|  |  | ||||||
|  | import org.junit.jupiter.api.Test; | ||||||
|  |  | ||||||
|  | import java.net.InetSocketAddress; | ||||||
|  | import java.util.Collections; | ||||||
|  |  | ||||||
|  | import static org.junit.jupiter.api.Assertions.assertEquals; | ||||||
|  |  | ||||||
|  | public class AddressRuleTest | ||||||
|  | { | ||||||
|  |     @Test | ||||||
|  |     public void matchesPort() | ||||||
|  |     { | ||||||
|  |         Iterable<AddressRule> rules = Collections.singletonList( AddressRule.parse( | ||||||
|  |             "127.0.0.1", 8080, | ||||||
|  |             new PartialOptions( Action.ALLOW, null, null, null, null ) | ||||||
|  |         ) ); | ||||||
|  |  | ||||||
|  |         assertEquals( apply( rules, "localhost", 8080 ).action, Action.ALLOW ); | ||||||
|  |         assertEquals( apply( rules, "localhost", 8081 ).action, Action.DENY ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private Options apply( Iterable<AddressRule> rules, String host, int port ) | ||||||
|  |     { | ||||||
|  |         return AddressRule.apply( rules, host, new InetSocketAddress( host, port ) ); | ||||||
|  |     } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 Merith-TK
					Merith-TK