mirror of
				https://github.com/SquidDev-CC/CC-Tweaked
				synced 2025-10-31 13:42:59 +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 | ||||
|  | ||||
| # Minecraft properties | ||||
| mc_version=1.16.3 | ||||
| mc_version=1.16.2 | ||||
| mappings_version=31 | ||||
|  | ||||
| # Dependencies | ||||
|   | ||||
							
								
								
									
										20
									
								
								patchwork.md
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								patchwork.md
									
									
									
									
									
								
							| @@ -53,3 +53,23 @@ Fix additional `-` in docs | ||||
|  | ||||
| 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) { | ||||
|         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), | ||||
|                 Stream.of(whitelist) | ||||
|                         .map(x -> AddressRule.parse(x, Action.ALLOW.toPartial())) | ||||
|                         .map( x -> AddressRule.parse( x, null, Action.ALLOW.toPartial())) | ||||
|                         .filter(Objects::nonNull)) | ||||
|                 .collect(Collectors.toList()); | ||||
|     } | ||||
|   | ||||
| @@ -21,14 +21,14 @@ public class CheckUrl extends Resource<CheckUrl> { | ||||
|     private static final String EVENT = "http_check"; | ||||
|     private final IAPIEnvironment environment; | ||||
|     private final String address; | ||||
|     private final String host; | ||||
|     private final URI uri; | ||||
|     private Future<?> future; | ||||
|  | ||||
|     public CheckUrl(ResourceGroup<CheckUrl> limiter, IAPIEnvironment environment, String address, URI uri) { | ||||
|         super(limiter); | ||||
|         this.environment = environment; | ||||
|         this.address = address; | ||||
|         this.host = uri.getHost(); | ||||
|         this.uri = uri; | ||||
|     } | ||||
|  | ||||
|     public void run() { | ||||
| @@ -45,8 +45,9 @@ public class CheckUrl extends Resource<CheckUrl> { | ||||
|         } | ||||
|  | ||||
|         try { | ||||
|             InetSocketAddress netAddress = NetworkUtils.getAddress(this.host, 80, false); | ||||
|             NetworkUtils.getOptions(this.host, netAddress); | ||||
|             boolean ssl = uri.getScheme().equalsIgnoreCase( "https" ); | ||||
|             InetSocketAddress netAddress = NetworkUtils.getAddress( uri, ssl ); | ||||
|             NetworkUtils.getOptions( uri.getHost(), netAddress ); | ||||
|  | ||||
|             if (this.tryClose()) { | ||||
|                 this.environment.queueEvent(EVENT, this.address, true); | ||||
|   | ||||
| @@ -7,6 +7,7 @@ | ||||
| package dan200.computercraft.core.apis.http; | ||||
|  | ||||
| import java.net.InetSocketAddress; | ||||
| import java.net.URI; | ||||
| import java.security.KeyStore; | ||||
| import java.util.concurrent.ExecutorService; | ||||
| 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. | ||||
|      * | ||||
| @@ -125,7 +141,7 @@ public final class NetworkUtils { | ||||
|      * @throws HTTPRequestException If the host is not permitted | ||||
|      */ | ||||
|     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) { | ||||
|             throw new HTTPRequestException("Domain not permitted"); | ||||
|         } | ||||
|   | ||||
| @@ -8,6 +8,7 @@ package dan200.computercraft.core.apis.http.options; | ||||
|  | ||||
| import java.net.Inet6Address; | ||||
| import java.net.InetAddress; | ||||
| import java.net.InetSocketAddress; | ||||
| import java.util.regex.Pattern; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
| @@ -26,15 +27,22 @@ public final class AddressRule { | ||||
|     public static final int WEBSOCKET_MESSAGE = 128 * 1024; | ||||
|     private final HostRange ip; | ||||
|     private final Pattern domainPattern; | ||||
|     private final Integer port; | ||||
|     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.domainPattern = domainPattern; | ||||
|         this.partial = partial; | ||||
| 		this.port = port; | ||||
|     } | ||||
|  | ||||
|     @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('/'); | ||||
|         if (cidr >= 0) { | ||||
|             String addressStr = filter.substring(0, cidr); | ||||
| @@ -73,14 +81,14 @@ public final class AddressRule { | ||||
|                 size -= 8; | ||||
|             } | ||||
|  | ||||
|             return new AddressRule(new HostRange(minBytes, maxBytes), null, partial); | ||||
|             return new AddressRule(new HostRange(minBytes, maxBytes), null, port, partial); | ||||
|         } else { | ||||
|             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; | ||||
|         boolean hasMany = false; | ||||
|  | ||||
| @@ -109,10 +117,13 @@ public final class AddressRule { | ||||
|      * Determine whether the given address matches a series of patterns. | ||||
|      * | ||||
|      * @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. | ||||
|      */ | ||||
|     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.matcher(domain) | ||||
|                                   .matches()) { | ||||
|   | ||||
| @@ -9,6 +9,8 @@ package dan200.computercraft.core.apis.http.options; | ||||
| public class AddressRuleConfig { | ||||
|     // 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 ) | ||||
|     //    { | ||||
|     //        CommentedConfig config = InMemoryCommentedFormat.defaultInstance().createConfig( ConcurrentHashMap::new ); | ||||
| @@ -39,17 +41,19 @@ public class AddressRuleConfig { | ||||
|     //    { | ||||
|     //        String hostObj = get( builder, "host", String.class ).orElse( null ); | ||||
|     //        return hostObj != null && checkEnum( builder, "action", Action.class ) | ||||
|     //            && check( builder, "port", Number.class ) | ||||
|     //            && check( builder, "timeout", Number.class ) | ||||
|     //            && check( builder, "max_upload", Number.class ) | ||||
|     //            && check( builder, "max_download", Number.class ) | ||||
|     //            && check( builder, "websocket_message", Number.class ) | ||||
|     //            && AddressRule.parse( hostObj, PartialOptions.DEFAULT ) != null; | ||||
|     //            && AddressRule.parse( hostObj, port, PartialOptions.DEFAULT ) != null; | ||||
|     //    } | ||||
|     // | ||||
|     //    @Nullable | ||||
|     //    public static AddressRule parseRule( UnmodifiableConfig builder ) | ||||
|     //    { | ||||
|     //        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; | ||||
|     // | ||||
|     //        Action action = getEnum( builder, "action", Action.class ).orElse( null ); | ||||
| @@ -66,7 +70,7 @@ public class AddressRuleConfig { | ||||
|     //            websocketMessage | ||||
|     //        ); | ||||
|     // | ||||
|     //        return AddressRule.parse( hostObj, options ); | ||||
|     //        return AddressRule.parse( hostObj, port, options ); | ||||
|     //    } | ||||
|     // | ||||
|     //    private static <T> boolean check( UnmodifiableConfig config, String field, Class<T> klass ) | ||||
|   | ||||
| @@ -131,7 +131,7 @@ public class HttpRequest extends Resource<HttpRequest> { | ||||
|         try { | ||||
|             boolean ssl = uri.getScheme() | ||||
|                              .equalsIgnoreCase("https"); | ||||
|             InetSocketAddress socketAddress = NetworkUtils.getAddress(uri.getHost(), uri.getPort(), ssl); | ||||
|             InetSocketAddress socketAddress = NetworkUtils.getAddress(uri, ssl); | ||||
|             Options options = NetworkUtils.getOptions(uri.getHost(), socketAddress); | ||||
|             SslContext sslContext = ssl ? NetworkUtils.getSslContext() : null; | ||||
|  | ||||
|   | ||||
| @@ -117,7 +117,7 @@ public class Websocket extends Resource<Websocket> { | ||||
|             boolean ssl = this.uri.getScheme() | ||||
|                                   .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); | ||||
|             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