mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2024-09-28 15:08:47 +00:00
Document HTTP rules a little better
It turns out we don't document the "port" option anywhere, so probably worth doing a bit of an overhaul here. - Expand the top-level HTTP rules comment, clarifying how things are matched and describing each field. - Improve the comments on the default HTTP rule. We now also describe the $private rule and its motivation. - Don't drop/ignore invalid rules. This gets written back to the original config file, so is very annoying! Instead we now log an error and convert the rule into a "deny all" rule, which should make it obvious something is wrong.
This commit is contained in:
parent
655d5aeca8
commit
ecf880ed82
@ -4,21 +4,19 @@
|
|||||||
|
|
||||||
package dan200.computercraft.shared.config;
|
package dan200.computercraft.shared.config;
|
||||||
|
|
||||||
|
import com.electronwill.nightconfig.core.CommentedConfig;
|
||||||
import com.electronwill.nightconfig.core.Config;
|
import com.electronwill.nightconfig.core.Config;
|
||||||
import com.electronwill.nightconfig.core.InMemoryCommentedFormat;
|
import com.electronwill.nightconfig.core.InMemoryCommentedFormat;
|
||||||
import com.electronwill.nightconfig.core.UnmodifiableConfig;
|
import com.electronwill.nightconfig.core.UnmodifiableConfig;
|
||||||
import dan200.computercraft.core.apis.http.options.Action;
|
import dan200.computercraft.core.apis.http.options.Action;
|
||||||
import dan200.computercraft.core.apis.http.options.AddressRule;
|
import dan200.computercraft.core.apis.http.options.AddressRule;
|
||||||
|
import dan200.computercraft.core.apis.http.options.InvalidRuleException;
|
||||||
import dan200.computercraft.core.apis.http.options.PartialOptions;
|
import dan200.computercraft.core.apis.http.options.PartialOptions;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import java.util.*;
|
||||||
import java.util.Locale;
|
import java.util.function.Consumer;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.OptionalInt;
|
|
||||||
import java.util.OptionalLong;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses, checks and generates {@link Config}s for {@link AddressRule}.
|
* Parses, checks and generates {@link Config}s for {@link AddressRule}.
|
||||||
@ -26,12 +24,27 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
class AddressRuleConfig {
|
class AddressRuleConfig {
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(AddressRuleConfig.class);
|
private static final Logger LOG = LoggerFactory.getLogger(AddressRuleConfig.class);
|
||||||
|
|
||||||
public static UnmodifiableConfig makeRule(String host, Action action) {
|
private static final AddressRule REJECT_ALL = AddressRule.parse("*", OptionalInt.empty(), Action.DENY.toPartial());
|
||||||
var config = InMemoryCommentedFormat.defaultInstance().createConfig(ConcurrentHashMap::new);
|
|
||||||
config.add("host", host);
|
public static List<UnmodifiableConfig> defaultRules() {
|
||||||
config.add("action", action.name().toLowerCase(Locale.ROOT));
|
return List.of(
|
||||||
|
makeRule(config -> {
|
||||||
|
config.setComment("host", """
|
||||||
|
The magic "$private" host matches all private address ranges, such as localhost and 192.168.0.0/16.
|
||||||
|
This rule prevents computers accessing internal services, and is strongly recommended.""");
|
||||||
|
config.add("host", "$private");
|
||||||
|
|
||||||
|
config.setComment("action", "Deny all requests to private IP addresses.");
|
||||||
|
config.add("action", Action.DENY.name().toLowerCase(Locale.ROOT));
|
||||||
|
}),
|
||||||
|
makeRule(config -> {
|
||||||
|
config.setComment("host", """
|
||||||
|
The wildcard "*" rule matches all remaining hosts.""");
|
||||||
|
config.add("host", "*");
|
||||||
|
|
||||||
|
config.setComment("action", "Allow all non-denied hosts.");
|
||||||
|
config.add("action", Action.ALLOW.name().toLowerCase(Locale.ROOT));
|
||||||
|
|
||||||
if (host.equals("*") && action == Action.ALLOW) {
|
|
||||||
config.setComment("max_download", """
|
config.setComment("max_download", """
|
||||||
The maximum size (in bytes) that a computer can download in a single request.
|
The maximum size (in bytes) that a computer can download in a single request.
|
||||||
Note that responses may receive more data than allowed, but this data will not
|
Note that responses may receive more data than allowed, but this data will not
|
||||||
@ -48,27 +61,28 @@ class AddressRuleConfig {
|
|||||||
|
|
||||||
config.setComment("use_proxy", "Enable use of the HTTP/SOCKS proxy if it is configured.");
|
config.setComment("use_proxy", "Enable use of the HTTP/SOCKS proxy if it is configured.");
|
||||||
config.set("use_proxy", false);
|
config.set("use_proxy", false);
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static UnmodifiableConfig makeRule(Consumer<CommentedConfig> setup) {
|
||||||
|
var config = InMemoryCommentedFormat.defaultInstance().createConfig(LinkedHashMap::new);
|
||||||
|
setup.accept(config);
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean checkRule(UnmodifiableConfig builder) {
|
public static AddressRule parseRule(UnmodifiableConfig builder) {
|
||||||
var hostObj = get(builder, "host", String.class).orElse(null);
|
try {
|
||||||
var port = unboxOptInt(get(builder, "port", Number.class));
|
return doParseRule(builder);
|
||||||
return hostObj != null && checkEnum(builder, "action", Action.class)
|
} catch (InvalidRuleException e) {
|
||||||
&& check(builder, "port", Number.class)
|
LOG.error("Malformed HTTP rule: {} HTTP will NOT work until this is fixed.", e.getMessage());
|
||||||
&& check(builder, "max_upload", Number.class)
|
return REJECT_ALL;
|
||||||
&& check(builder, "max_download", Number.class)
|
}
|
||||||
&& check(builder, "websocket_message", Number.class)
|
|
||||||
&& check(builder, "use_proxy", Boolean.class)
|
|
||||||
&& AddressRule.parse(hostObj, port, PartialOptions.DEFAULT) != null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
public static AddressRule doParseRule(UnmodifiableConfig builder) {
|
||||||
public static AddressRule parseRule(UnmodifiableConfig builder) {
|
|
||||||
var hostObj = get(builder, "host", String.class).orElse(null);
|
var hostObj = get(builder, "host", String.class).orElse(null);
|
||||||
if (hostObj == null) return null;
|
if (hostObj == null) throw new InvalidRuleException("No 'host' specified");
|
||||||
|
|
||||||
var action = getEnum(builder, "action", Action.class).orElse(null);
|
var action = getEnum(builder, "action", Action.class).orElse(null);
|
||||||
var port = unboxOptInt(get(builder, "port", Number.class));
|
var port = unboxOptInt(get(builder, "port", Number.class));
|
||||||
@ -88,38 +102,19 @@ class AddressRuleConfig {
|
|||||||
return AddressRule.parse(hostObj, port, options);
|
return AddressRule.parse(hostObj, port, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> boolean check(UnmodifiableConfig config, String field, Class<T> klass) {
|
|
||||||
var value = config.get(field);
|
|
||||||
if (value == null || klass.isInstance(value)) return true;
|
|
||||||
|
|
||||||
LOG.warn("HTTP rule's {} is not a {}.", field, klass.getSimpleName());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static <T extends Enum<T>> boolean checkEnum(UnmodifiableConfig config, String field, Class<T> klass) {
|
|
||||||
var value = config.get(field);
|
|
||||||
if (value == null) return true;
|
|
||||||
|
|
||||||
if (!(value instanceof String)) {
|
|
||||||
LOG.warn("HTTP rule's {} is not a string", field);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parseEnum(klass, (String) value) == null) {
|
|
||||||
LOG.warn("HTTP rule's {} is not a known option", field);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static <T> Optional<T> get(UnmodifiableConfig config, String field, Class<T> klass) {
|
private static <T> Optional<T> get(UnmodifiableConfig config, String field, Class<T> klass) {
|
||||||
var value = config.get(field);
|
var value = config.get(field);
|
||||||
return klass.isInstance(value) ? Optional.of(klass.cast(value)) : Optional.empty();
|
if (value == null) return Optional.empty();
|
||||||
|
if (klass.isInstance(value)) return Optional.of(klass.cast(value));
|
||||||
|
|
||||||
|
throw new InvalidRuleException(String.format(
|
||||||
|
"Field '%s' should be a '%s' but is a %s.",
|
||||||
|
field, klass.getSimpleName(), value.getClass().getSimpleName()
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T extends Enum<T>> Optional<T> getEnum(UnmodifiableConfig config, String field, Class<T> klass) {
|
private static <T extends Enum<T>> Optional<T> getEnum(UnmodifiableConfig config, String field, Class<T> klass) {
|
||||||
return get(config, field, String.class).map(x -> parseEnum(klass, x));
|
return get(config, field, String.class).map(x -> parseEnum(field, klass, x));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static OptionalLong unboxOptLong(Optional<? extends Number> value) {
|
private static OptionalLong unboxOptLong(Optional<? extends Number> value) {
|
||||||
@ -130,11 +125,14 @@ class AddressRuleConfig {
|
|||||||
return value.map(Number::intValue).map(OptionalInt::of).orElse(OptionalInt.empty());
|
return value.map(Number::intValue).map(OptionalInt::of).orElse(OptionalInt.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
private static <T extends Enum<T>> T parseEnum(String field, Class<T> klass, String x) {
|
||||||
private static <T extends Enum<T>> T parseEnum(Class<T> klass, String x) {
|
|
||||||
for (var value : klass.getEnumConstants()) {
|
for (var value : klass.getEnumConstants()) {
|
||||||
if (value.name().equalsIgnoreCase(x)) return value;
|
if (value.name().equalsIgnoreCase(x)) return value;
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
|
throw new InvalidRuleException(String.format(
|
||||||
|
"Field '%s' should be one of %s, but is '%s'.",
|
||||||
|
field, Arrays.stream(klass.getEnumConstants()).map(Enum::name).toList(), x
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ import dan200.computercraft.api.ComputerCraftAPI;
|
|||||||
import dan200.computercraft.core.CoreConfig;
|
import dan200.computercraft.core.CoreConfig;
|
||||||
import dan200.computercraft.core.Logging;
|
import dan200.computercraft.core.Logging;
|
||||||
import dan200.computercraft.core.apis.http.NetworkUtils;
|
import dan200.computercraft.core.apis.http.NetworkUtils;
|
||||||
import dan200.computercraft.core.apis.http.options.Action;
|
|
||||||
import dan200.computercraft.core.apis.http.options.ProxyType;
|
import dan200.computercraft.core.apis.http.options.ProxyType;
|
||||||
import dan200.computercraft.core.computer.mainthread.MainThreadConfig;
|
import dan200.computercraft.core.computer.mainthread.MainThreadConfig;
|
||||||
import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer;
|
import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer;
|
||||||
@ -20,9 +19,7 @@ import org.apache.logging.log4j.core.filter.MarkerFilter;
|
|||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public final class ConfigSpec {
|
public final class ConfigSpec {
|
||||||
@ -182,9 +179,9 @@ public final class ConfigSpec {
|
|||||||
|
|
||||||
httpEnabled = builder
|
httpEnabled = builder
|
||||||
.comment("""
|
.comment("""
|
||||||
Enable the "http" API on Computers. This also disables the "pastebin" and "wget"
|
Enable the "http" API on Computers. Disabling this also disables the "pastebin" and
|
||||||
programs, that many users rely on. It's recommended to leave this on and use the
|
"wget" programs, that many users rely on. It's recommended to leave this on and use
|
||||||
"rules" config option to impose more fine-grained control.""")
|
the "rules" config option to impose more fine-grained control.""")
|
||||||
.define("enabled", CoreConfig.httpEnabled);
|
.define("enabled", CoreConfig.httpEnabled);
|
||||||
|
|
||||||
httpWebsocketEnabled = builder
|
httpWebsocketEnabled = builder
|
||||||
@ -194,16 +191,23 @@ public final class ConfigSpec {
|
|||||||
httpRules = builder
|
httpRules = builder
|
||||||
.comment("""
|
.comment("""
|
||||||
A list of rules which control behaviour of the "http" API for specific domains or
|
A list of rules which control behaviour of the "http" API for specific domains or
|
||||||
IPs. Each rule is an item with a 'host' to match against, and a series of
|
IPs. Each rule matches against a hostname and an optional port, and then sets several
|
||||||
properties. Rules are evaluated in order, meaning earlier rules override later
|
properties for the request. Rules are evaluated in order, meaning earlier rules override
|
||||||
ones.
|
later ones.
|
||||||
The host may be a domain name ("pastebin.com"), wildcard ("*.pastebin.com") or
|
|
||||||
CIDR notation ("127.0.0.0/8").
|
Valid properties:
|
||||||
If no rules, the domain is blocked.""")
|
- "host" (required): The domain or IP address this rule matches. This may be a domain name
|
||||||
.defineList("rules", Arrays.asList(
|
("pastebin.com"), wildcard ("*.pastebin.com") or CIDR notation ("127.0.0.0/8").
|
||||||
AddressRuleConfig.makeRule("$private", Action.DENY),
|
- "port" (optional): Only match requests for a specific port, such as 80 or 443.
|
||||||
AddressRuleConfig.makeRule("*", Action.ALLOW)
|
|
||||||
), x -> x instanceof UnmodifiableConfig && AddressRuleConfig.checkRule((UnmodifiableConfig) x));
|
- "action" (optional): Whether to allow or deny this request.
|
||||||
|
- "max_download" (optional): The maximum size (in bytes) that a computer can download in this
|
||||||
|
request.
|
||||||
|
- "max_upload" (optional): The maximum size (in bytes) that a computer can upload in a this request.
|
||||||
|
- "max_websocket_message" (optional): The maximum size (in bytes) that a computer can send or
|
||||||
|
receive in one websocket packet.
|
||||||
|
- "use_proxy" (optional): Enable use of the HTTP/SOCKS proxy if it is configured.""")
|
||||||
|
.defineList("rules", AddressRuleConfig.defaultRules(), x -> x instanceof UnmodifiableConfig);
|
||||||
|
|
||||||
httpMaxRequests = builder
|
httpMaxRequests = builder
|
||||||
.comment("""
|
.comment("""
|
||||||
@ -395,8 +399,8 @@ public final class ConfigSpec {
|
|||||||
// HTTP
|
// HTTP
|
||||||
CoreConfig.httpEnabled = httpEnabled.get();
|
CoreConfig.httpEnabled = httpEnabled.get();
|
||||||
CoreConfig.httpWebsocketEnabled = httpWebsocketEnabled.get();
|
CoreConfig.httpWebsocketEnabled = httpWebsocketEnabled.get();
|
||||||
CoreConfig.httpRules = httpRules.get().stream()
|
|
||||||
.map(AddressRuleConfig::parseRule).filter(Objects::nonNull).toList();
|
CoreConfig.httpRules = httpRules.get().stream().map(AddressRuleConfig::parseRule).toList();
|
||||||
|
|
||||||
CoreConfig.httpMaxRequests = httpMaxRequests.get();
|
CoreConfig.httpMaxRequests = httpMaxRequests.get();
|
||||||
CoreConfig.httpMaxWebsockets = httpMaxWebsockets.get();
|
CoreConfig.httpMaxWebsockets = httpMaxWebsockets.get();
|
||||||
|
@ -5,10 +5,7 @@
|
|||||||
package dan200.computercraft.core.apis.http.options;
|
package dan200.computercraft.core.apis.http.options;
|
||||||
|
|
||||||
import com.google.common.net.InetAddresses;
|
import com.google.common.net.InetAddresses;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@ -19,8 +16,6 @@ import java.util.regex.Pattern;
|
|||||||
* @see AddressRule#apply(Iterable, String, InetSocketAddress) for the actual handling of this rule.
|
* @see AddressRule#apply(Iterable, String, InetSocketAddress) for the actual handling of this rule.
|
||||||
*/
|
*/
|
||||||
interface AddressPredicate {
|
interface AddressPredicate {
|
||||||
Logger LOG = LoggerFactory.getLogger(AddressPredicate.class);
|
|
||||||
|
|
||||||
default boolean matches(String domain) {
|
default boolean matches(String domain) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -51,28 +46,25 @@ interface AddressPredicate {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static HostRange parse(String addressStr, String prefixSizeStr) {
|
public static HostRange parse(String addressStr, String prefixSizeStr) {
|
||||||
int prefixSize;
|
int prefixSize;
|
||||||
try {
|
try {
|
||||||
prefixSize = Integer.parseInt(prefixSizeStr);
|
prefixSize = Integer.parseInt(prefixSizeStr);
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
LOG.error(
|
throw new InvalidRuleException(String.format(
|
||||||
"Malformed http whitelist/blacklist entry '{}': Cannot extract size of CIDR mask from '{}'.",
|
"Invalid host host '%s': Cannot extract size of CIDR mask from '%s'.",
|
||||||
addressStr + '/' + prefixSizeStr, prefixSizeStr
|
addressStr + '/' + prefixSizeStr, prefixSizeStr
|
||||||
);
|
));
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InetAddress address;
|
InetAddress address;
|
||||||
try {
|
try {
|
||||||
address = InetAddresses.forString(addressStr);
|
address = InetAddresses.forString(addressStr);
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
LOG.error(
|
throw new InvalidRuleException(String.format(
|
||||||
"Malformed http whitelist/blacklist entry '{}': Cannot extract IP address from '{}'.",
|
"Invalid host '%s': Cannot extract IP address from '%s'.",
|
||||||
addressStr + '/' + prefixSizeStr, addressStr
|
addressStr + '/' + prefixSizeStr, addressStr
|
||||||
);
|
));
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mask the bytes of the IP address.
|
// Mask the bytes of the IP address.
|
||||||
@ -112,7 +104,6 @@ interface AddressPredicate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
final class PrivatePattern implements AddressPredicate {
|
final class PrivatePattern implements AddressPredicate {
|
||||||
static final PrivatePattern INSTANCE = new PrivatePattern();
|
static final PrivatePattern INSTANCE = new PrivatePattern();
|
||||||
|
|
||||||
|
@ -35,14 +35,13 @@ public final class AddressRule {
|
|||||||
this.port = port;
|
this.port = port;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static AddressRule parse(String filter, OptionalInt port, PartialOptions partial) {
|
public static AddressRule parse(String filter, OptionalInt port, PartialOptions partial) {
|
||||||
var cidr = filter.indexOf('/');
|
var cidr = filter.indexOf('/');
|
||||||
if (cidr >= 0) {
|
if (cidr >= 0) {
|
||||||
var addressStr = filter.substring(0, cidr);
|
var addressStr = filter.substring(0, cidr);
|
||||||
var prefixSizeStr = filter.substring(cidr + 1);
|
var prefixSizeStr = filter.substring(cidr + 1);
|
||||||
var range = HostRange.parse(addressStr, prefixSizeStr);
|
var range = HostRange.parse(addressStr, prefixSizeStr);
|
||||||
return range == null ? null : new AddressRule(range, port, partial);
|
return new AddressRule(range, port, partial);
|
||||||
} else if (filter.equalsIgnoreCase("$private")) {
|
} else if (filter.equalsIgnoreCase("$private")) {
|
||||||
return new AddressRule(PrivatePattern.INSTANCE, port, partial);
|
return new AddressRule(PrivatePattern.INSTANCE, port, partial);
|
||||||
} else {
|
} else {
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.core.apis.http.options;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.util.OptionalInt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throw when a {@link AddressRule} cannot be parsed.
|
||||||
|
*
|
||||||
|
* @see AddressRule#parse(String, OptionalInt, PartialOptions)
|
||||||
|
* @see AddressPredicate.HostRange#parse(String, String)
|
||||||
|
*/
|
||||||
|
public class InvalidRuleException extends RuntimeException {
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1303376302865132758L;
|
||||||
|
|
||||||
|
public InvalidRuleException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
@ -90,9 +90,8 @@ while running do
|
|||||||
|
|
||||||
local results = table.pack(exception.try(func))
|
local results = table.pack(exception.try(func))
|
||||||
if results[1] then
|
if results[1] then
|
||||||
local n = 1
|
for i = 2, results.n do
|
||||||
while n < results.n do
|
local value = results[i]
|
||||||
local value = results[n + 1]
|
|
||||||
local ok, serialised = pcall(pretty.pretty, value, {
|
local ok, serialised = pcall(pretty.pretty, value, {
|
||||||
function_args = settings.get("lua.function_args"),
|
function_args = settings.get("lua.function_args"),
|
||||||
function_source = settings.get("lua.function_source"),
|
function_source = settings.get("lua.function_source"),
|
||||||
@ -102,7 +101,6 @@ while running do
|
|||||||
else
|
else
|
||||||
print(tostring(value))
|
print(tostring(value))
|
||||||
end
|
end
|
||||||
n = n + 1
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
printError(results[2])
|
printError(results[2])
|
||||||
|
@ -99,7 +99,7 @@
|
|||||||
"gui.computercraft.config.http.bandwidth.global_upload.tooltip": "The number of bytes which can be uploaded in a second. This is shared across all computers. (bytes/s).\nRange: > 1",
|
"gui.computercraft.config.http.bandwidth.global_upload.tooltip": "The number of bytes which can be uploaded in a second. This is shared across all computers. (bytes/s).\nRange: > 1",
|
||||||
"gui.computercraft.config.http.bandwidth.tooltip": "Limits bandwidth used by computers.",
|
"gui.computercraft.config.http.bandwidth.tooltip": "Limits bandwidth used by computers.",
|
||||||
"gui.computercraft.config.http.enabled": "Enable the HTTP API",
|
"gui.computercraft.config.http.enabled": "Enable the HTTP API",
|
||||||
"gui.computercraft.config.http.enabled.tooltip": "Enable the \"http\" API on Computers. This also disables the \"pastebin\" and \"wget\"\nprograms, that many users rely on. It's recommended to leave this on and use the\n\"rules\" config option to impose more fine-grained control.",
|
"gui.computercraft.config.http.enabled.tooltip": "Enable the \"http\" API on Computers. Disabling this also disables the \"pastebin\" and\n\"wget\" programs, that many users rely on. It's recommended to leave this on and use\nthe \"rules\" config option to impose more fine-grained control.",
|
||||||
"gui.computercraft.config.http.max_requests": "Maximum concurrent requests",
|
"gui.computercraft.config.http.max_requests": "Maximum concurrent requests",
|
||||||
"gui.computercraft.config.http.max_requests.tooltip": "The number of http requests a computer can make at one time. Additional requests\nwill be queued, and sent when the running requests have finished. Set to 0 for\nunlimited.\nRange: > 0",
|
"gui.computercraft.config.http.max_requests.tooltip": "The number of http requests a computer can make at one time. Additional requests\nwill be queued, and sent when the running requests have finished. Set to 0 for\nunlimited.\nRange: > 0",
|
||||||
"gui.computercraft.config.http.max_websockets": "Maximum concurrent websockets",
|
"gui.computercraft.config.http.max_websockets": "Maximum concurrent websockets",
|
||||||
@ -113,7 +113,7 @@
|
|||||||
"gui.computercraft.config.http.proxy.type": "Proxy type",
|
"gui.computercraft.config.http.proxy.type": "Proxy type",
|
||||||
"gui.computercraft.config.http.proxy.type.tooltip": "The type of proxy to use.\nAllowed Values: HTTP, HTTPS, SOCKS4, SOCKS5",
|
"gui.computercraft.config.http.proxy.type.tooltip": "The type of proxy to use.\nAllowed Values: HTTP, HTTPS, SOCKS4, SOCKS5",
|
||||||
"gui.computercraft.config.http.rules": "Allow/deny rules",
|
"gui.computercraft.config.http.rules": "Allow/deny rules",
|
||||||
"gui.computercraft.config.http.rules.tooltip": "A list of rules which control behaviour of the \"http\" API for specific domains or\nIPs. Each rule is an item with a 'host' to match against, and a series of\nproperties. Rules are evaluated in order, meaning earlier rules override later\nones.\nThe host may be a domain name (\"pastebin.com\"), wildcard (\"*.pastebin.com\") or\nCIDR notation (\"127.0.0.0/8\").\nIf no rules, the domain is blocked.",
|
"gui.computercraft.config.http.rules.tooltip": "A list of rules which control behaviour of the \"http\" API for specific domains or\nIPs. Each rule matches against a hostname and an optional port, and then sets several\nproperties for the request. Rules are evaluated in order, meaning earlier rules override\nlater ones.\n\nValid properties:\n - \"host\" (required): The domain or IP address this rule matches. This may be a domain name\n (\"pastebin.com\"), wildcard (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\").\n - \"port\" (optional): Only match requests for a specific port, such as 80 or 443.\n\n - \"action\" (optional): Whether to allow or deny this request.\n - \"max_download\" (optional): The maximum size (in bytes) that a computer can download in this\n request.\n - \"max_upload\" (optional): The maximum size (in bytes) that a computer can upload in a this request.\n - \"max_websocket_message\" (optional): The maximum size (in bytes) that a computer can send or\n receive in one websocket packet.\n - \"use_proxy\" (optional): Enable use of the HTTP/SOCKS proxy if it is configured.",
|
||||||
"gui.computercraft.config.http.tooltip": "Controls the HTTP API",
|
"gui.computercraft.config.http.tooltip": "Controls the HTTP API",
|
||||||
"gui.computercraft.config.http.websocket_enabled": "Enable websockets",
|
"gui.computercraft.config.http.websocket_enabled": "Enable websockets",
|
||||||
"gui.computercraft.config.http.websocket_enabled.tooltip": "Enable use of http websockets. This requires the \"http_enable\" option to also be true.",
|
"gui.computercraft.config.http.websocket_enabled.tooltip": "Enable use of http websockets. This requires the \"http_enable\" option to also be true.",
|
||||||
|
@ -99,7 +99,7 @@
|
|||||||
"gui.computercraft.config.http.bandwidth.global_upload.tooltip": "The number of bytes which can be uploaded in a second. This is shared across all computers. (bytes/s).\nRange: > 1",
|
"gui.computercraft.config.http.bandwidth.global_upload.tooltip": "The number of bytes which can be uploaded in a second. This is shared across all computers. (bytes/s).\nRange: > 1",
|
||||||
"gui.computercraft.config.http.bandwidth.tooltip": "Limits bandwidth used by computers.",
|
"gui.computercraft.config.http.bandwidth.tooltip": "Limits bandwidth used by computers.",
|
||||||
"gui.computercraft.config.http.enabled": "Enable the HTTP API",
|
"gui.computercraft.config.http.enabled": "Enable the HTTP API",
|
||||||
"gui.computercraft.config.http.enabled.tooltip": "Enable the \"http\" API on Computers. This also disables the \"pastebin\" and \"wget\"\nprograms, that many users rely on. It's recommended to leave this on and use the\n\"rules\" config option to impose more fine-grained control.",
|
"gui.computercraft.config.http.enabled.tooltip": "Enable the \"http\" API on Computers. Disabling this also disables the \"pastebin\" and\n\"wget\" programs, that many users rely on. It's recommended to leave this on and use\nthe \"rules\" config option to impose more fine-grained control.",
|
||||||
"gui.computercraft.config.http.max_requests": "Maximum concurrent requests",
|
"gui.computercraft.config.http.max_requests": "Maximum concurrent requests",
|
||||||
"gui.computercraft.config.http.max_requests.tooltip": "The number of http requests a computer can make at one time. Additional requests\nwill be queued, and sent when the running requests have finished. Set to 0 for\nunlimited.\nRange: > 0",
|
"gui.computercraft.config.http.max_requests.tooltip": "The number of http requests a computer can make at one time. Additional requests\nwill be queued, and sent when the running requests have finished. Set to 0 for\nunlimited.\nRange: > 0",
|
||||||
"gui.computercraft.config.http.max_websockets": "Maximum concurrent websockets",
|
"gui.computercraft.config.http.max_websockets": "Maximum concurrent websockets",
|
||||||
@ -113,7 +113,7 @@
|
|||||||
"gui.computercraft.config.http.proxy.type": "Proxy type",
|
"gui.computercraft.config.http.proxy.type": "Proxy type",
|
||||||
"gui.computercraft.config.http.proxy.type.tooltip": "The type of proxy to use.\nAllowed Values: HTTP, HTTPS, SOCKS4, SOCKS5",
|
"gui.computercraft.config.http.proxy.type.tooltip": "The type of proxy to use.\nAllowed Values: HTTP, HTTPS, SOCKS4, SOCKS5",
|
||||||
"gui.computercraft.config.http.rules": "Allow/deny rules",
|
"gui.computercraft.config.http.rules": "Allow/deny rules",
|
||||||
"gui.computercraft.config.http.rules.tooltip": "A list of rules which control behaviour of the \"http\" API for specific domains or\nIPs. Each rule is an item with a 'host' to match against, and a series of\nproperties. Rules are evaluated in order, meaning earlier rules override later\nones.\nThe host may be a domain name (\"pastebin.com\"), wildcard (\"*.pastebin.com\") or\nCIDR notation (\"127.0.0.0/8\").\nIf no rules, the domain is blocked.",
|
"gui.computercraft.config.http.rules.tooltip": "A list of rules which control behaviour of the \"http\" API for specific domains or\nIPs. Each rule matches against a hostname and an optional port, and then sets several\nproperties for the request. Rules are evaluated in order, meaning earlier rules override\nlater ones.\n\nValid properties:\n - \"host\" (required): The domain or IP address this rule matches. This may be a domain name\n (\"pastebin.com\"), wildcard (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\").\n - \"port\" (optional): Only match requests for a specific port, such as 80 or 443.\n\n - \"action\" (optional): Whether to allow or deny this request.\n - \"max_download\" (optional): The maximum size (in bytes) that a computer can download in this\n request.\n - \"max_upload\" (optional): The maximum size (in bytes) that a computer can upload in a this request.\n - \"max_websocket_message\" (optional): The maximum size (in bytes) that a computer can send or\n receive in one websocket packet.\n - \"use_proxy\" (optional): Enable use of the HTTP/SOCKS proxy if it is configured.",
|
||||||
"gui.computercraft.config.http.tooltip": "Controls the HTTP API",
|
"gui.computercraft.config.http.tooltip": "Controls the HTTP API",
|
||||||
"gui.computercraft.config.http.websocket_enabled": "Enable websockets",
|
"gui.computercraft.config.http.websocket_enabled": "Enable websockets",
|
||||||
"gui.computercraft.config.http.websocket_enabled.tooltip": "Enable use of http websockets. This requires the \"http_enable\" option to also be true.",
|
"gui.computercraft.config.http.websocket_enabled.tooltip": "Enable use of http websockets. This requires the \"http_enable\" option to also be true.",
|
||||||
|
Loading…
Reference in New Issue
Block a user