From ea390d85e79cf4584222522415a85221720c9a74 Mon Sep 17 00:00:00 2001 From: Jonathan Cobb Date: Thu, 10 Dec 2020 07:34:42 -0500 Subject: [PATCH] add whois geo location and scrub codebase for safe shell args --- bin/first_time_ubuntu.sh | 2 +- .../bblock/BubbleBlockAppConfigDriver.java | 6 +- .../bubble/cloud/CloudRegionRelative.java | 12 + .../bubble/cloud/dns/DnsServiceDriver.java | 19 +- .../GeoLocateServiceDriverBase.java | 20 +- .../bubble/cloud/geoLocation/GeoLocation.java | 6 + ...ver.java => MaxMindGeoLocationDriver.java} | 2 +- .../cloud/geoLocation/whois/WhoisConfig.java | 16 ++ .../whois/WhoisGeoLocationDriver.java | 71 +++++ .../java/bubble/main/RekeyDatabaseMain.java | 9 +- .../model/cloud/RegionalServiceDriver.java | 26 +- .../resources/bill/AccountPlansResource.java | 2 +- .../cloud/CloudServiceRegionsResource.java | 4 +- .../resources/cloud/NetworksResource.java | 6 +- .../rule/bblock/BubbleBlockRuleDriver.java | 5 +- .../main/java/bubble/server/BubbleServer.java | 4 +- .../boot/PublicUpgradeMonitorService.java | 7 - .../service/cloud/StandardNetworkService.java | 3 +- .../bubble/service/packer/PackerService.java | 3 +- .../cloud/geoLocation/country-locations.json | 246 ++++++++++++++++++ .../models/defaults/cloudService.json | 17 +- config/activation.json | 24 +- utils/abp-parser | 2 +- utils/cobbzilla-utils | 2 +- utils/cobbzilla-wizard | 2 +- 25 files changed, 462 insertions(+), 54 deletions(-) rename bubble-server/src/main/java/bubble/cloud/geoLocation/maxmind/{MaxMindDriver.java => MaxMindGeoLocationDriver.java} (94%) create mode 100644 bubble-server/src/main/java/bubble/cloud/geoLocation/whois/WhoisConfig.java create mode 100644 bubble-server/src/main/java/bubble/cloud/geoLocation/whois/WhoisGeoLocationDriver.java create mode 100644 bubble-server/src/main/resources/bubble/cloud/geoLocation/country-locations.json diff --git a/bin/first_time_ubuntu.sh b/bin/first_time_ubuntu.sh index 7c2cb551..2d5a0a53 100755 --- a/bin/first_time_ubuntu.sh +++ b/bin/first_time_ubuntu.sh @@ -26,7 +26,7 @@ sudo apt update -y || die "Error running apt update" sudo apt upgrade -y || die "Error running apt upgrade" # Install packages -sudo apt install openjdk-11-jdk maven postgresql redis-server jq python3 python3-pip npm webpack curl zip unzip -y || die "Error installing apt packages" +sudo apt install openjdk-11-jdk maven postgresql redis-server jq python3 python3-pip npm webpack curl zip unzip whois -y || die "Error installing apt packages" sudo pip3 install setuptools psycopg2-binary || die "Error installing pip packages" # Install packer diff --git a/bubble-server/src/main/java/bubble/app/bblock/BubbleBlockAppConfigDriver.java b/bubble-server/src/main/java/bubble/app/bblock/BubbleBlockAppConfigDriver.java index 71752edf..9301a79b 100644 --- a/bubble-server/src/main/java/bubble/app/bblock/BubbleBlockAppConfigDriver.java +++ b/bubble-server/src/main/java/bubble/app/bblock/BubbleBlockAppConfigDriver.java @@ -19,7 +19,6 @@ import bubble.server.BubbleConfiguration; import com.fasterxml.jackson.databind.JsonNode; import lombok.extern.slf4j.Slf4j; import org.cobbzilla.util.collection.ExpirationMap; -import org.cobbzilla.util.string.ValidationRegexes; import org.cobbzilla.wizard.validation.ValidationResult; import org.springframework.beans.factory.annotation.Autowired; @@ -36,8 +35,7 @@ import static org.cobbzilla.util.http.HttpSchemes.isHttpOrHttps; import static org.cobbzilla.util.http.URIUtil.getHost; import static org.cobbzilla.util.http.URIUtil.getPath; import static org.cobbzilla.util.json.JsonUtil.json; -import static org.cobbzilla.util.string.ValidationRegexes.HTTPS_PATTERN; -import static org.cobbzilla.util.string.ValidationRegexes.HTTP_PATTERN; +import static org.cobbzilla.util.string.ValidationRegexes.*; import static org.cobbzilla.wizard.model.BasicConstraintConstants.URL_MAXLEN; import static org.cobbzilla.wizard.resources.ResourceUtil.invalidEx; import static org.cobbzilla.wizard.resources.ResourceUtil.notFoundEx; @@ -213,7 +211,7 @@ public class BubbleBlockAppConfigDriver extends AppConfigDriverBase { } catch (Exception e) { throw invalidEx("err.testUrl.invalid", "Test URL was not valid", shortError(e)); } - if (empty(host) || !ValidationRegexes.HOST_PATTERN.matcher(host).matches()) { + if (empty(host) || !isHostname(host)) { throw invalidEx("err.testUrl.invalidHostname", "Test URL was not valid"); } diff --git a/bubble-server/src/main/java/bubble/cloud/CloudRegionRelative.java b/bubble-server/src/main/java/bubble/cloud/CloudRegionRelative.java index 2a4a4936..9bd24e77 100644 --- a/bubble-server/src/main/java/bubble/cloud/CloudRegionRelative.java +++ b/bubble-server/src/main/java/bubble/cloud/CloudRegionRelative.java @@ -10,6 +10,8 @@ import lombok.Setter; import lombok.experimental.Accessors; import org.cobbzilla.util.reflect.OpenApiSchema; +import java.util.Comparator; + import static org.cobbzilla.util.reflect.ReflectionUtil.copy; @NoArgsConstructor @Accessors(chain=true) @OpenApiSchema @@ -23,4 +25,14 @@ public class CloudRegionRelative extends CloudRegion { if (hasLocation()) distance = getLocation().distance(latitude, longitude); } + public static final CloudRegionRelativeComparator SORT_DISTANCE_THEN_NAME = new CloudRegionRelativeComparator(); + + public static class CloudRegionRelativeComparator implements Comparator { + @Override public int compare(CloudRegionRelative crr1, CloudRegionRelative crr2) { + final int diff = Double.compare(crr1.getDistance(), crr2.getDistance()); + if (diff != 0) return diff; + return crr1.getInternalName().compareTo(crr2.getInternalName()); + } + } + } diff --git a/bubble-server/src/main/java/bubble/cloud/dns/DnsServiceDriver.java b/bubble-server/src/main/java/bubble/cloud/dns/DnsServiceDriver.java index 0ce47773..2e25d7e9 100644 --- a/bubble-server/src/main/java/bubble/cloud/dns/DnsServiceDriver.java +++ b/bubble-server/src/main/java/bubble/cloud/dns/DnsServiceDriver.java @@ -16,10 +16,7 @@ import org.cobbzilla.util.string.StringUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; import static java.util.concurrent.TimeUnit.SECONDS; @@ -27,6 +24,8 @@ import static org.cobbzilla.util.daemon.ZillaRuntime.*; import static org.cobbzilla.util.dns.DnsRecord.OPT_NS_NAME; import static org.cobbzilla.util.network.NetworkUtil.IPv4_ALL_ADDRS; import static org.cobbzilla.util.network.NetworkUtil.ipEquals; +import static org.cobbzilla.util.string.StringUtil.safeShellArg; +import static org.cobbzilla.util.string.ValidationRegexes.isHostname; import static org.cobbzilla.util.system.CommandShell.execScript; import static org.cobbzilla.util.system.Sleep.sleep; @@ -61,11 +60,19 @@ public interface DnsServiceDriver extends CloudServiceDriver { static Collection dig(String host, DnsType type, String name) { return dig(host, 53, type, name); } static Collection dig(String host, int port, DnsType type, String name) { + if (!isHostname(host)) { + log.warn("dig: invalid host: "+host); + return Collections.emptyList(); + } + if (!isHostname(name)) { + log.warn("dig: invalid name: "+name); + return Collections.emptyList(); + } final String output = execScript("dig +tcp +short +nocomment " - + "@" + host + + "@" + safeShellArg(host) + " -p " + port + " -t " + type.name() - + " -q " + name); + + " -q " + safeShellArg(name)); log.info("dig @"+host+" "+name+": output: "+output.trim()); final List records = new ArrayList<>(); for (String line : output.split("[\n]+")) { diff --git a/bubble-server/src/main/java/bubble/cloud/geoLocation/GeoLocateServiceDriverBase.java b/bubble-server/src/main/java/bubble/cloud/geoLocation/GeoLocateServiceDriverBase.java index 6e673dbd..f0c8d1ec 100644 --- a/bubble-server/src/main/java/bubble/cloud/geoLocation/GeoLocateServiceDriverBase.java +++ b/bubble-server/src/main/java/bubble/cloud/geoLocation/GeoLocateServiceDriverBase.java @@ -22,14 +22,20 @@ import org.cobbzilla.wizard.cache.redis.RedisService; import org.springframework.beans.factory.annotation.Autowired; import java.io.*; +import java.util.Arrays; import java.util.List; -import java.util.concurrent.TimeUnit; +import java.util.Map; import java.util.regex.Pattern; +import java.util.stream.Collectors; +import static java.util.concurrent.TimeUnit.DAYS; import static java.util.concurrent.TimeUnit.SECONDS; +import static java.util.function.Function.identity; import static org.cobbzilla.util.daemon.ZillaRuntime.*; import static org.cobbzilla.util.http.HttpSchemes.SCHEME_FILE; +import static org.cobbzilla.util.http.HttpUtil.getHeadMetadata; import static org.cobbzilla.util.io.FileUtil.*; +import static org.cobbzilla.util.io.StreamUtil.stream2string; import static org.cobbzilla.util.json.JsonUtil.json; import static org.cobbzilla.util.system.Sleep.sleep; import static org.cobbzilla.wizard.cache.redis.RedisService.EX; @@ -38,7 +44,7 @@ import static org.cobbzilla.wizard.resources.ResourceUtil.invalidEx; @Slf4j public abstract class GeoLocateServiceDriverBase extends CloudServiceDriverBase implements GeoLocateServiceDriver { - public static final long CACHE_TTL = TimeUnit.DAYS.toSeconds(20); + public static final long CACHE_TTL = DAYS.toSeconds(20); public static final long ERROR_TTL = SECONDS.toSeconds(20); private static final int MAX_FILE_RETRIES = 5; @@ -57,6 +63,14 @@ public abstract class GeoLocateServiceDriverBase extends CloudServiceDriverBa @Autowired private RedisService redis; @Getter(lazy=true) private final RedisService cache = redis.prefixNamespace(getClass().getName()+"_cache_"); + @Getter(lazy=true) private final Map countryMap = initCountryMap(); + private Map initCountryMap() { + final String countryJson = stream2string("bubble/cloud/geoLocation/country-locations.json"); + final GeoLocation[] countryLocations = json(countryJson, GeoLocation[].class); + return Arrays.stream(countryLocations) + .collect(Collectors.toMap(GeoLocation::getCountry, identity())); + } + @Override public GeoLocation geolocate (String ip) { String val = getCache().get(ip); long ttl = CACHE_TTL; @@ -90,7 +104,7 @@ public abstract class GeoLocateServiceDriverBase extends CloudServiceDriverBa final String urlWithLicense = HandlebarsUtil.apply(getHandlebars(), url, getCredentials().newContext(), '[', ']') .replace("&", "&"); final HttpRequestBean request = new HttpRequestBean(urlWithLicense).setHeaders(headers); - final HttpMeta meta = HttpUtil.getHeadMetadata(request); + final HttpMeta meta = getHeadMetadata(request); final String uniq = hashOf(url, headers); final String dbKey = "dbcache_" + uniq; diff --git a/bubble-server/src/main/java/bubble/cloud/geoLocation/GeoLocation.java b/bubble-server/src/main/java/bubble/cloud/geoLocation/GeoLocation.java index 797bddc8..448926ec 100644 --- a/bubble-server/src/main/java/bubble/cloud/geoLocation/GeoLocation.java +++ b/bubble-server/src/main/java/bubble/cloud/geoLocation/GeoLocation.java @@ -19,6 +19,7 @@ import org.cobbzilla.wizard.model.entityconfig.annotations.ECField; import javax.persistence.Transient; import static org.cobbzilla.util.daemon.ZillaRuntime.*; +import static org.cobbzilla.util.reflect.ReflectionUtil.copy; @NoArgsConstructor @Accessors(chain=true) @ToString(of={"lat", "lon"}) @OpenApiSchema public class GeoLocation { @@ -34,6 +35,11 @@ public class GeoLocation { public static final GeoLocation NULL_LOCATION = new GeoLocation().setLat("-1.0").setLon("-1.0"); public static final double INVALID_LOCATION = -1.0; + public GeoLocation(String country) { + copy(this, NULL_LOCATION); + setCountry(country); + } + @Getter @Setter private String country; public boolean hasCountry() { return !empty(country); } diff --git a/bubble-server/src/main/java/bubble/cloud/geoLocation/maxmind/MaxMindDriver.java b/bubble-server/src/main/java/bubble/cloud/geoLocation/maxmind/MaxMindGeoLocationDriver.java similarity index 94% rename from bubble-server/src/main/java/bubble/cloud/geoLocation/maxmind/MaxMindDriver.java rename to bubble-server/src/main/java/bubble/cloud/geoLocation/maxmind/MaxMindGeoLocationDriver.java index ce6c9767..171101a9 100644 --- a/bubble-server/src/main/java/bubble/cloud/geoLocation/maxmind/MaxMindDriver.java +++ b/bubble-server/src/main/java/bubble/cloud/geoLocation/maxmind/MaxMindGeoLocationDriver.java @@ -16,7 +16,7 @@ import java.net.InetAddress; import static org.cobbzilla.util.daemon.ZillaRuntime.die; -public class MaxMindDriver extends GeoLocateServiceDriverBase { +public class MaxMindGeoLocationDriver extends GeoLocateServiceDriverBase { private DatabaseReader reader; diff --git a/bubble-server/src/main/java/bubble/cloud/geoLocation/whois/WhoisConfig.java b/bubble-server/src/main/java/bubble/cloud/geoLocation/whois/WhoisConfig.java new file mode 100644 index 00000000..4e6d727b --- /dev/null +++ b/bubble-server/src/main/java/bubble/cloud/geoLocation/whois/WhoisConfig.java @@ -0,0 +1,16 @@ +package bubble.cloud.geoLocation.whois; + +import lombok.Getter; +import lombok.Setter; + +import static org.cobbzilla.util.daemon.ZillaRuntime.empty; + +public class WhoisConfig { + + @Getter @Setter private String host; + public boolean hasHost() { return !empty(host); } + + @Getter @Setter private Integer port; + public boolean hasPort() { return port != null && port > 0 && port < 65536; } + +} diff --git a/bubble-server/src/main/java/bubble/cloud/geoLocation/whois/WhoisGeoLocationDriver.java b/bubble-server/src/main/java/bubble/cloud/geoLocation/whois/WhoisGeoLocationDriver.java new file mode 100644 index 00000000..ddcfdf24 --- /dev/null +++ b/bubble-server/src/main/java/bubble/cloud/geoLocation/whois/WhoisGeoLocationDriver.java @@ -0,0 +1,71 @@ +package bubble.cloud.geoLocation.whois; + +import bubble.cloud.geoLocation.GeoLocateServiceDriverBase; +import bubble.cloud.geoLocation.GeoLocation; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.exec.CommandLine; +import org.cobbzilla.util.system.CommandResult; + +import java.util.Arrays; +import java.util.Optional; + +import static bubble.cloud.geoLocation.GeoLocation.NULL_LOCATION; +import static org.cobbzilla.util.daemon.ZillaRuntime.*; +import static org.cobbzilla.util.string.StringUtil.safeShellArg; +import static org.cobbzilla.util.string.ValidationRegexes.isHostname; +import static org.cobbzilla.util.system.CommandShell.exec; +import static org.cobbzilla.util.system.CommandShell.execScript; + +@Slf4j +public class WhoisGeoLocationDriver extends GeoLocateServiceDriverBase { + + @Getter(lazy=true) private final String whois = initWhois(); + private String initWhois() { + final String cmd = execScript("which whois"); + return empty(cmd) ? die("initWhois: 'whois' command not found") : cmd; + } + + @Override protected GeoLocation _geolocate(String ip) { + try { + final CommandLine commandLine = new CommandLine(getWhois()); + final WhoisConfig config = getConfig(); + if (config.hasHost()) { + final String host = config.getHost(); + if (!isHostname(host)) return die("_geolocate: invalid host: "+host); + commandLine.addArgument("-h").addArgument(safeShellArg(host)); + } + if (config.hasPort()) commandLine.addArgument("-p").addArgument(""+config.getPort()); + commandLine.addArgument(ip); + + final CommandResult result = exec(commandLine); + if (!result.isZeroExitStatus()) { + log.error("_geolocate: 'whois' had non-zero exit status: " + result.getExitStatus() + "\nstderr=" + result.getStderr()); + return NULL_LOCATION; + } + + final String[] lines = result.getStdout().split("\n"); + final Optional countryLine = Arrays.stream(lines) + .filter(line -> line.trim().startsWith("Country:")) + .findFirst(); + if (countryLine.isEmpty()) { + log.warn("_geolocate: No 'Country:' found in 'whois' output"); + return NULL_LOCATION; + } + final String[] parts = countryLine.get().split("\\s+"); + if (parts.length != 2) { + log.warn("_geolocate: invalid Country: line: "+countryLine); + return NULL_LOCATION; + } + final String country = parts[1]; + + final GeoLocation found = getCountryMap().get(country.toUpperCase()); + return found == null ? NULL_LOCATION : found; + + } catch (Exception e) { + log.error("_geolocate: error: "+shortError(e)); + return NULL_LOCATION; + } + } + +} diff --git a/bubble-server/src/main/java/bubble/main/RekeyDatabaseMain.java b/bubble-server/src/main/java/bubble/main/RekeyDatabaseMain.java index c2d34efb..e91d79ec 100644 --- a/bubble-server/src/main/java/bubble/main/RekeyDatabaseMain.java +++ b/bubble-server/src/main/java/bubble/main/RekeyDatabaseMain.java @@ -19,6 +19,7 @@ import java.util.concurrent.atomic.AtomicReference; import static java.util.concurrent.TimeUnit.MINUTES; import static org.cobbzilla.util.daemon.ZillaRuntime.background; import static org.cobbzilla.util.daemon.ZillaRuntime.getJava; +import static org.cobbzilla.util.string.StringUtil.safeShellArg; public class RekeyDatabaseMain extends BaseMain { @@ -93,13 +94,13 @@ public class RekeyDatabaseMain extends BaseMain { commandLine = commandLine .addArgument(clazz.getName()) .addArgument(RekeyOptions.LONGOPT_DB) - .addArgument(dbName) + .addArgument(safeShellArg(dbName)) .addArgument(RekeyOptions.LONGOPT_DB_USER) - .addArgument(options.getDbUser()) + .addArgument(safeShellArg(options.getDbUser())) .addArgument(RekeyOptions.LONGOPT_DB_PASS) - .addArgument(options.getDbPass()) + .addArgument(safeShellArg(options.getDbPass())) .addArgument(RekeyOptions.LONGOPT_KEY) - .addArgument(key) + .addArgument(safeShellArg(key)) .addArgument(RekeyOptions.LONGOPT_PORT) .addArgument("" + options.getPort()); diff --git a/bubble-server/src/main/java/bubble/model/cloud/RegionalServiceDriver.java b/bubble-server/src/main/java/bubble/model/cloud/RegionalServiceDriver.java index 03ab704c..4c566d57 100644 --- a/bubble-server/src/main/java/bubble/model/cloud/RegionalServiceDriver.java +++ b/bubble-server/src/main/java/bubble/model/cloud/RegionalServiceDriver.java @@ -16,8 +16,8 @@ import java.util.Collection; import java.util.List; import java.util.stream.Collectors; +import static bubble.cloud.CloudRegionRelative.SORT_DISTANCE_THEN_NAME; import static bubble.cloud.geoLocation.GeoLocation.*; -import static java.util.Comparator.comparingDouble; import static org.cobbzilla.util.daemon.ZillaRuntime.shortError; public interface RegionalServiceDriver { @@ -51,24 +51,23 @@ public interface RegionalServiceDriver { } if (regions != null) { for (CloudRegion region : regions) { + if (exclude != null && exclude.contains(new CloudAndRegion(c, region))) { + log.info("findClosestRegions: skipping excluded region: "+region); + continue; + } if (!region.hasLocation() || region.getLocation() == NULL_LOCATION) { // region has no location, it will always match with a distance of zero - final CloudRegionRelative r = new CloudRegionRelative(region); - r.setDistance(0).setCloud(c.getUuid()); - allRegions.add(r); + addRegionWithUnknownDistance(allRegions, c, region); continue; } if (latitude == INVALID_LOCATION && longitude == INVALID_LOCATION) { // region has a location, we can never match with invalid coordinates + addRegionWithUnknownDistance(allRegions, c, region); continue; } if (footprint != null && region.hasLocation() && !footprint.isAllowedCountry(region.getLocation().getCountry())) { continue; } - if (exclude != null && exclude.contains(new CloudAndRegion(c, region))) { - log.info("findClosestRegions: skipping excluded region: "+region); - continue; - } final CloudRegionRelative r = new CloudRegionRelative(region); r.setCloud(c.getUuid()); if (latLonIsValid && latitude >= 0 && longitude >= 0) { @@ -80,10 +79,19 @@ public interface RegionalServiceDriver { } } } - allRegions.sort(comparingDouble(CloudRegionRelative::getDistance)); + allRegions.sort(SORT_DISTANCE_THEN_NAME); return allRegions; } + private static void addRegionWithUnknownDistance(List allRegions, + CloudService c, + CloudRegion region) { + final CloudRegionRelative r = new CloudRegionRelative(region); + r.setDistance(0); + r.setCloud(c.getUuid()); + allRegions.add(r); + } + List getRegions(); default List getRegions(BubbleFootprint footprint) { diff --git a/bubble-server/src/main/java/bubble/resources/bill/AccountPlansResource.java b/bubble-server/src/main/java/bubble/resources/bill/AccountPlansResource.java index 58b60258..a877c1cd 100644 --- a/bubble-server/src/main/java/bubble/resources/bill/AccountPlansResource.java +++ b/bubble-server/src/main/java/bubble/resources/bill/AccountPlansResource.java @@ -172,7 +172,7 @@ public class AccountPlansResource extends AccountOwnedResource findRegions(List clouds, BubbleFootprint footprint) { diff --git a/bubble-server/src/main/java/bubble/resources/cloud/NetworksResource.java b/bubble-server/src/main/java/bubble/resources/cloud/NetworksResource.java index c1abb42c..b63e6314 100644 --- a/bubble-server/src/main/java/bubble/resources/cloud/NetworksResource.java +++ b/bubble-server/src/main/java/bubble/resources/cloud/NetworksResource.java @@ -30,7 +30,10 @@ import org.glassfish.grizzly.http.server.Request; import org.glassfish.jersey.server.ContainerRequest; import org.springframework.beans.factory.annotation.Autowired; -import javax.ws.rs.*; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; @@ -164,6 +167,7 @@ public class NetworksResource extends AccountOwnedResource { final File envFile = getEnvFile(args); if (envFile == null) return die("loadEnvironment: no env file found"); if (!envFile.exists()) return die("loadEnvironment: env file does not exist: "+abs(envFile)); - env.putAll(CommandShell.loadShellExports(envFile)); + env.putAll(loadShellExports(envFile)); } catch (Exception e) { log.warn("Error loading environment: "+e); } diff --git a/bubble-server/src/main/java/bubble/service/boot/PublicUpgradeMonitorService.java b/bubble-server/src/main/java/bubble/service/boot/PublicUpgradeMonitorService.java index df947593..b1984779 100644 --- a/bubble-server/src/main/java/bubble/service/boot/PublicUpgradeMonitorService.java +++ b/bubble-server/src/main/java/bubble/service/boot/PublicUpgradeMonitorService.java @@ -8,16 +8,11 @@ import bubble.model.cloud.BubbleVersionInfo; import bubble.server.BubbleConfiguration; import lombok.Cleanup; import lombok.extern.slf4j.Slf4j; -import org.cobbzilla.util.daemon.SimpleDaemon; -import org.cobbzilla.util.io.Decompressors; -import org.cobbzilla.util.io.FileUtil; import org.cobbzilla.util.io.TempDir; -import org.cobbzilla.wizard.model.SemanticVersion; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.io.File; -import java.util.regex.Pattern; import static java.util.concurrent.TimeUnit.HOURS; import static java.util.concurrent.TimeUnit.SECONDS; @@ -26,8 +21,6 @@ import static org.cobbzilla.util.http.HttpUtil.url2file; import static org.cobbzilla.util.http.HttpUtil.url2string; import static org.cobbzilla.util.io.Decompressors.extract; import static org.cobbzilla.util.io.FileUtil.*; -import static org.cobbzilla.util.system.CommandShell.execScript; -import static org.cobbzilla.wizard.model.SemanticVersion.SEMANTIC_VERSION_RE; import static org.cobbzilla.wizard.model.SemanticVersion.isNewerVersion; @Service @Slf4j diff --git a/bubble-server/src/main/java/bubble/service/cloud/StandardNetworkService.java b/bubble-server/src/main/java/bubble/service/cloud/StandardNetworkService.java index b1a20bc0..59569c25 100644 --- a/bubble-server/src/main/java/bubble/service/cloud/StandardNetworkService.java +++ b/bubble-server/src/main/java/bubble/service/cloud/StandardNetworkService.java @@ -89,6 +89,7 @@ import static org.cobbzilla.util.daemon.ZillaRuntime.*; import static org.cobbzilla.util.io.FileUtil.*; import static org.cobbzilla.util.io.StreamUtil.stream2string; import static org.cobbzilla.util.json.JsonUtil.json; +import static org.cobbzilla.util.string.StringUtil.safeShellArg; import static org.cobbzilla.util.system.CommandShell.chmod; import static org.cobbzilla.util.system.Sleep.sleep; import static org.cobbzilla.util.time.TimeUtil.formatDuration; @@ -304,7 +305,7 @@ public class StandardNetworkService implements NetworkService { + "-o StrictHostKeyChecking=no " + "-o PreferredAuthentications=publickey " + "-i " + abs(sshKeyFile); - final String sshTarget = node.getUser() + "@" + computeDriver.getNodeIp4(node); + final String sshTarget = safeShellArg(node.getUser() + "@" + computeDriver.getNodeIp4(node)); boolean setupOk = false; final String nodeUser = node.getUser(); diff --git a/bubble-server/src/main/java/bubble/service/packer/PackerService.java b/bubble-server/src/main/java/bubble/service/packer/PackerService.java index 0c274186..d48cd209 100644 --- a/bubble-server/src/main/java/bubble/service/packer/PackerService.java +++ b/bubble-server/src/main/java/bubble/service/packer/PackerService.java @@ -28,6 +28,7 @@ import static org.cobbzilla.util.io.FileUtil.abs; import static org.cobbzilla.util.io.FileUtil.mkdirOrDie; import static org.cobbzilla.util.io.StreamUtil.stream2string; import static org.cobbzilla.util.security.ShaUtil.sha256_file; +import static org.cobbzilla.util.string.StringUtil.safeShellArg; import static org.cobbzilla.util.string.StringUtil.splitAndTrim; import static org.cobbzilla.util.system.CommandShell.chmod; import static org.cobbzilla.util.system.CommandShell.execScript; @@ -125,7 +126,7 @@ public class PackerService { final File privateKeyFile = new File(keyDir, PACKER_KEY_NAME); if (!pubKeyFile.exists() || !privateKeyFile.exists()) { final String comment = configuration.getShortVersion() + "_" + configuration.getJarSha(); - execScript("ssh-keygen -t rsa -q -N '' -C '"+comment+"' -f "+abs(privateKeyFile)); + execScript("ssh-keygen -t rsa -q -N '' -C '"+safeShellArg(comment)+"' -f "+abs(privateKeyFile)); if (!pubKeyFile.exists() || !privateKeyFile.exists()) return die("initPackerKey: error creating packer key"); } return pub ? pubKeyFile : privateKeyFile; diff --git a/bubble-server/src/main/resources/bubble/cloud/geoLocation/country-locations.json b/bubble-server/src/main/resources/bubble/cloud/geoLocation/country-locations.json new file mode 100644 index 00000000..cbc5d44f --- /dev/null +++ b/bubble-server/src/main/resources/bubble/cloud/geoLocation/country-locations.json @@ -0,0 +1,246 @@ +[ + {"name": "AD", "lat": 42.546245, "lon": 1.601554}, + {"name": "AE", "lat": 23.424076, "lon": 53.847818}, + {"name": "AF", "lat": 33.93911, "lon": 67.709953}, + {"name": "AG", "lat": 17.060816, "lon": -61.796428}, + {"name": "AI", "lat": 18.220554, "lon": -63.068615}, + {"name": "AL", "lat": 41.153332, "lon": 20.168331}, + {"name": "AM", "lat": 40.069099, "lon": 45.038189}, + {"name": "AN", "lat": 12.226079, "lon": -69.060087}, + {"name": "AO", "lat": -11.202692, "lon": 17.873887}, + {"name": "AQ", "lat": -75.250973, "lon": -0.071389}, + {"name": "AR", "lat": -38.416097, "lon": -63.616672}, + {"name": "AS", "lat": -14.270972, "lon": -170.132217}, + {"name": "AT", "lat": 47.516231, "lon": 14.550072}, + {"name": "AU", "lat": -25.274398, "lon": 133.775136}, + {"name": "AW", "lat": 12.52111, "lon": -69.968338}, + {"name": "AZ", "lat": 40.143105, "lon": 47.576927}, + {"name": "BA", "lat": 43.915886, "lon": 17.679076}, + {"name": "BB", "lat": 13.193887, "lon": -59.543198}, + {"name": "BD", "lat": 23.684994, "lon": 90.356331}, + {"name": "BE", "lat": 50.503887, "lon": 4.469936}, + {"name": "BF", "lat": 12.238333, "lon": -1.561593}, + {"name": "BG", "lat": 42.733883, "lon": 25.48583}, + {"name": "BH", "lat": 25.930414, "lon": 50.637772}, + {"name": "BI", "lat": -3.373056, "lon": 29.918886}, + {"name": "BJ", "lat": 9.30769, "lon": 2.315834}, + {"name": "BM", "lat": 32.321384, "lon": -64.75737}, + {"name": "BN", "lat": 4.535277, "lon": 114.727669}, + {"name": "BO", "lat": -16.290154, "lon": -63.588653}, + {"name": "BR", "lat": -14.235004, "lon": -51.92528}, + {"name": "BS", "lat": 25.03428, "lon": -77.39628}, + {"name": "BT", "lat": 27.514162, "lon": 90.433601}, + {"name": "BV", "lat": -54.423199, "lon": 3.413194}, + {"name": "BW", "lat": -22.328474, "lon": 24.684866}, + {"name": "BY", "lat": 53.709807, "lon": 27.953389}, + {"name": "BZ", "lat": 17.189877, "lon": -88.49765}, + {"name": "CA", "lat": 56.130366, "lon": -106.346771}, + {"name": "CC", "lat": -12.164165, "lon": 96.870956}, + {"name": "CD", "lat": -4.038333, "lon": 21.758664}, + {"name": "CF", "lat": 6.611111, "lon": 20.939444}, + {"name": "CG", "lat": -0.228021, "lon": 15.827659}, + {"name": "CH", "lat": 46.818188, "lon": 8.227512}, + {"name": "CI", "lat": 7.539989, "lon": -5.54708}, + {"name": "CK", "lat": -21.236736, "lon": -159.777671}, + {"name": "CL", "lat": -35.675147, "lon": -71.542969}, + {"name": "CM", "lat": 7.369722, "lon": 12.354722}, + {"name": "CN", "lat": 35.86166, "lon": 104.195397}, + {"name": "CO", "lat": 4.570868, "lon": -74.297333}, + {"name": "CR", "lat": 9.748917, "lon": -83.753428}, + {"name": "CU", "lat": 21.521757, "lon": -77.781167}, + {"name": "CV", "lat": 16.002082, "lon": -24.013197}, + {"name": "CX", "lat": -10.447525, "lon": 105.690449}, + {"name": "CY", "lat": 35.126413, "lon": 33.429859}, + {"name": "CZ", "lat": 49.817492, "lon": 15.472962}, + {"name": "DE", "lat": 51.165691, "lon": 10.451526}, + {"name": "DJ", "lat": 11.825138, "lon": 42.590275}, + {"name": "DK", "lat": 56.26392, "lon": 9.501785}, + {"name": "DM", "lat": 15.414999, "lon": -61.370976}, + {"name": "DO", "lat": 18.735693, "lon": -70.162651}, + {"name": "DZ", "lat": 28.033886, "lon": 1.659626}, + {"name": "EC", "lat": -1.831239, "lon": -78.183406}, + {"name": "EE", "lat": 58.595272, "lon": 25.013607}, + {"name": "EG", "lat": 26.820553, "lon": 30.802498}, + {"name": "EH", "lat": 24.215527, "lon": -12.885834}, + {"name": "ER", "lat": 15.179384, "lon": 39.782334}, + {"name": "ES", "lat": 40.463667, "lon": -3.74922}, + {"name": "ET", "lat": 9.145, "lon": 40.489673}, + {"name": "FI", "lat": 61.92411, "lon": 25.748151}, + {"name": "FJ", "lat": -16.578193, "lon": 179.414413}, + {"name": "FK", "lat": -51.796253, "lon": -59.523613}, + {"name": "FM", "lat": 7.425554, "lon": 150.550812}, + {"name": "FO", "lat": 61.892635, "lon": -6.911806}, + {"name": "FR", "lat": 46.227638, "lon": 2.213749}, + {"name": "GA", "lat": -0.803689, "lon": 11.609444}, + {"name": "GB", "lat": 55.378051, "lon": -3.435973}, + {"name": "GD", "lat": 12.262776, "lon": -61.604171}, + {"name": "GE", "lat": 42.315407, "lon": 43.356892}, + {"name": "GF", "lat": 3.933889, "lon": -53.125782}, + {"name": "GG", "lat": 49.465691, "lon": -2.585278}, + {"name": "GH", "lat": 7.946527, "lon": -1.023194}, + {"name": "GI", "lat": 36.137741, "lon": -5.345374}, + {"name": "GL", "lat": 71.706936, "lon": -42.604303}, + {"name": "GM", "lat": 13.443182, "lon": -15.310139}, + {"name": "GN", "lat": 9.945587, "lon": -9.696645}, + {"name": "GP", "lat": 16.995971, "lon": -62.067641}, + {"name": "GQ", "lat": 1.650801, "lon": 10.267895}, + {"name": "GR", "lat": 39.074208, "lon": 21.824312}, + {"name": "GS", "lat": -54.429579, "lon": -36.587909}, + {"name": "GT", "lat": 15.783471, "lon": -90.230759}, + {"name": "GU", "lat": 13.444304, "lon": 144.793731}, + {"name": "GW", "lat": 11.803749, "lon": -15.180413}, + {"name": "GY", "lat": 4.860416, "lon": -58.93018}, + {"name": "GZ", "lat": 31.354676, "lon": 34.308825}, + {"name": "HK", "lat": 22.396428, "lon": 114.109497}, + {"name": "HM", "lat": -53.08181, "lon": 73.504158}, + {"name": "HN", "lat": 15.199999, "lon": -86.241905}, + {"name": "HR", "lat": 45.1, "lon": 15.2}, + {"name": "HT", "lat": 18.971187, "lon": -72.285215}, + {"name": "HU", "lat": 47.162494, "lon": 19.503304}, + {"name": "ID", "lat": -0.789275, "lon": 113.921327}, + {"name": "IE", "lat": 53.41291, "lon": -8.24389}, + {"name": "IL", "lat": 31.046051, "lon": 34.851612}, + {"name": "IM", "lat": 54.236107, "lon": -4.548056}, + {"name": "IN", "lat": 20.593684, "lon": 78.96288}, + {"name": "IO", "lat": -6.343194, "lon": 71.876519}, + {"name": "IQ", "lat": 33.223191, "lon": 43.679291}, + {"name": "IR", "lat": 32.427908, "lon": 53.688046}, + {"name": "IS", "lat": 64.963051, "lon": -19.020835}, + {"name": "IT", "lat": 41.87194, "lon": 12.56738}, + {"name": "JE", "lat": 49.214439, "lon": -2.13125}, + {"name": "JM", "lat": 18.109581, "lon": -77.297508}, + {"name": "JO", "lat": 30.585164, "lon": 36.238414}, + {"name": "JP", "lat": 36.204824, "lon": 138.252924}, + {"name": "KE", "lat": -0.023559, "lon": 37.906193}, + {"name": "KG", "lat": 41.20438, "lon": 74.766098}, + {"name": "KH", "lat": 12.565679, "lon": 104.990963}, + {"name": "KI", "lat": -3.370417, "lon": -168.734039}, + {"name": "KM", "lat": -11.875001, "lon": 43.872219}, + {"name": "KN", "lat": 17.357822, "lon": -62.782998}, + {"name": "KP", "lat": 40.339852, "lon": 127.510093}, + {"name": "KR", "lat": 35.907757, "lon": 127.766922}, + {"name": "KW", "lat": 29.31166, "lon": 47.481766}, + {"name": "KY", "lat": 19.513469, "lon": -80.566956}, + {"name": "KZ", "lat": 48.019573, "lon": 66.923684}, + {"name": "LA", "lat": 19.85627, "lon": 102.495496}, + {"name": "LB", "lat": 33.854721, "lon": 35.862285}, + {"name": "LC", "lat": 13.909444, "lon": -60.978893}, + {"name": "LI", "lat": 47.166, "lon": 9.555373}, + {"name": "LK", "lat": 7.873054, "lon": 80.771797}, + {"name": "LR", "lat": 6.428055, "lon": -9.429499}, + {"name": "LS", "lat": -29.609988, "lon": 28.233608}, + {"name": "LT", "lat": 55.169438, "lon": 23.881275}, + {"name": "LU", "lat": 49.815273, "lon": 6.129583}, + {"name": "LV", "lat": 56.879635, "lon": 24.603189}, + {"name": "LY", "lat": 26.3351, "lon": 17.228331}, + {"name": "MA", "lat": 31.791702, "lon": -7.09262}, + {"name": "MC", "lat": 43.750298, "lon": 7.412841}, + {"name": "MD", "lat": 47.411631, "lon": 28.369885}, + {"name": "ME", "lat": 42.708678, "lon": 19.37439}, + {"name": "MG", "lat": -18.766947, "lon": 46.869107}, + {"name": "MH", "lat": 7.131474, "lon": 171.184478}, + {"name": "MK", "lat": 41.608635, "lon": 21.745275}, + {"name": "ML", "lat": 17.570692, "lon": -3.996166}, + {"name": "MM", "lat": 21.913965, "lon": 95.956223}, + {"name": "MN", "lat": 46.862496, "lon": 103.846656}, + {"name": "MO", "lat": 22.198745, "lon": 113.543873}, + {"name": "MP", "lat": 17.33083, "lon": 145.38469}, + {"name": "MQ", "lat": 14.641528, "lon": -61.024174}, + {"name": "MR", "lat": 21.00789, "lon": -10.940835}, + {"name": "MS", "lat": 16.742498, "lon": -62.187366}, + {"name": "MT", "lat": 35.937496, "lon": 14.375416}, + {"name": "MU", "lat": -20.348404, "lon": 57.552152}, + {"name": "MV", "lat": 3.202778, "lon": 73.22068}, + {"name": "MW", "lat": -13.254308, "lon": 34.301525}, + {"name": "MX", "lat": 23.634501, "lon": -102.552784}, + {"name": "MY", "lat": 4.210484, "lon": 101.975766}, + {"name": "MZ", "lat": -18.665695, "lon": 35.529562}, + {"name": "NA", "lat": -22.95764, "lon": 18.49041}, + {"name": "NC", "lat": -20.904305, "lon": 165.618042}, + {"name": "NE", "lat": 17.607789, "lon": 8.081666}, + {"name": "NF", "lat": -29.040835, "lon": 167.954712}, + {"name": "NG", "lat": 9.081999, "lon": 8.675277}, + {"name": "NI", "lat": 12.865416, "lon": -85.207229}, + {"name": "NL", "lat": 52.132633, "lon": 5.291266}, + {"name": "NO", "lat": 60.472024, "lon": 8.468946}, + {"name": "NP", "lat": 28.394857, "lon": 84.124008}, + {"name": "NR", "lat": -0.522778, "lon": 166.931503}, + {"name": "NU", "lat": -19.054445, "lon": -169.867233}, + {"name": "NZ", "lat": -40.900557, "lon": 174.885971}, + {"name": "OM", "lat": 21.512583, "lon": 55.923255}, + {"name": "PA", "lat": 8.537981, "lon": -80.782127}, + {"name": "PE", "lat": -9.189967, "lon": -75.015152}, + {"name": "PF", "lat": -17.679742, "lon": -149.406843}, + {"name": "PG", "lat": -6.314993, "lon": 143.95555}, + {"name": "PH", "lat": 12.879721, "lon": 121.774017}, + {"name": "PK", "lat": 30.375321, "lon": 69.345116}, + {"name": "PL", "lat": 51.919438, "lon": 19.145136}, + {"name": "PM", "lat": 46.941936, "lon": -56.27111}, + {"name": "PN", "lat": -24.703615, "lon": -127.439308}, + {"name": "PR", "lat": 18.220833, "lon": -66.590149}, + {"name": "PS", "lat": 31.952162, "lon": 35.233154}, + {"name": "PT", "lat": 39.399872, "lon": -8.224454}, + {"name": "PW", "lat": 7.51498, "lon": 134.58252}, + {"name": "PY", "lat": -23.442503, "lon": -58.443832}, + {"name": "QA", "lat": 25.354826, "lon": 51.183884}, + {"name": "RE", "lat": -21.115141, "lon": 55.536384}, + {"name": "RO", "lat": 45.943161, "lon": 24.96676}, + {"name": "RS", "lat": 44.016521, "lon": 21.005859}, + {"name": "RU", "lat": 61.52401, "lon": 105.318756}, + {"name": "RW", "lat": -1.940278, "lon": 29.873888}, + {"name": "SA", "lat": 23.885942, "lon": 45.079162}, + {"name": "SB", "lat": -9.64571, "lon": 160.156194}, + {"name": "SC", "lat": -4.679574, "lon": 55.491977}, + {"name": "SD", "lat": 12.862807, "lon": 30.217636}, + {"name": "SE", "lat": 60.128161, "lon": 18.643501}, + {"name": "SG", "lat": 1.352083, "lon": 103.819836}, + {"name": "SH", "lat": -24.143474, "lon": -10.030696}, + {"name": "SI", "lat": 46.151241, "lon": 14.995463}, + {"name": "SJ", "lat": 77.553604, "lon": 23.670272}, + {"name": "SK", "lat": 48.669026, "lon": 19.699024}, + {"name": "SL", "lat": 8.460555, "lon": -11.779889}, + {"name": "SM", "lat": 43.94236, "lon": 12.457777}, + {"name": "SN", "lat": 14.497401, "lon": -14.452362}, + {"name": "SO", "lat": 5.152149, "lon": 46.199616}, + {"name": "SR", "lat": 3.919305, "lon": -56.027783}, + {"name": "ST", "lat": 0.18636, "lon": 6.613081}, + {"name": "SV", "lat": 13.794185, "lon": -88.89653}, + {"name": "SY", "lat": 34.802075, "lon": 38.996815}, + {"name": "SZ", "lat": -26.522503, "lon": 31.465866}, + {"name": "TC", "lat": 21.694025, "lon": -71.797928}, + {"name": "TD", "lat": 15.454166, "lon": 18.732207}, + {"name": "TF", "lat": -49.280366, "lon": 69.348557}, + {"name": "TG", "lat": 8.619543, "lon": 0.824782}, + {"name": "TH", "lat": 15.870032, "lon": 100.992541}, + {"name": "TJ", "lat": 38.861034, "lon": 71.276093}, + {"name": "TK", "lat": -8.967363, "lon": -171.855881}, + {"name": "TL", "lat": -8.874217, "lon": 125.727539}, + {"name": "TM", "lat": 38.969719, "lon": 59.556278}, + {"name": "TN", "lat": 33.886917, "lon": 9.537499}, + {"name": "TO", "lat": -21.178986, "lon": -175.198242}, + {"name": "TR", "lat": 38.963745, "lon": 35.243322}, + {"name": "TT", "lat": 10.691803, "lon": -61.222503}, + {"name": "TV", "lat": -7.109535, "lon": 177.64933}, + {"name": "TW", "lat": 23.69781, "lon": 120.960515}, + {"name": "TZ", "lat": -6.369028, "lon": 34.888822}, + {"name": "UA", "lat": 48.379433, "lon": 31.16558}, + {"name": "UG", "lat": 1.373333, "lon": 32.290275}, + {"name": "US", "lat": 37.09024, "lon": -95.712891}, + {"name": "UY", "lat": -32.522779, "lon": -55.765835}, + {"name": "UZ", "lat": 41.377491, "lon": 64.585262}, + {"name": "VA", "lat": 41.902916, "lon": 12.453389}, + {"name": "VC", "lat": 12.984305, "lon": -61.287228}, + {"name": "VE", "lat": 6.42375, "lon": -66.58973}, + {"name": "VG", "lat": 18.420695, "lon": -64.639968}, + {"name": "VI", "lat": 18.335765, "lon": -64.896335}, + {"name": "VN", "lat": 14.058324, "lon": 108.277199}, + {"name": "VU", "lat": -15.376706, "lon": 166.959158}, + {"name": "WF", "lat": -13.768752, "lon": -177.156097}, + {"name": "WS", "lat": -13.759029, "lon": -172.104629}, + {"name": "XK", "lat": 42.602636, "lon": 20.902977}, + {"name": "YE", "lat": 15.552727, "lon": 48.516388}, + {"name": "YT", "lat": -12.8275, "lon": 45.166244}, + {"name": "ZA", "lat": -30.559482, "lon": 22.937506}, + {"name": "ZM", "lat": -13.133897, "lon": 27.849332}, + {"name": "ZW", "lat": -19.015438, "lon": 29.154857} +] diff --git a/bubble-server/src/main/resources/models/defaults/cloudService.json b/bubble-server/src/main/resources/models/defaults/cloudService.json index a6f91c71..290b0754 100644 --- a/bubble-server/src/main/resources/models/defaults/cloudService.json +++ b/bubble-server/src/main/resources/models/defaults/cloudService.json @@ -55,7 +55,7 @@ }, { - "name": "GoogleGeoCoder", + "name": "GoogleGeoCode", "type": "geoCode", "driverClass": "bubble.cloud.geoCode.google.GoogleGeoCodeDriver", "credentials": { "params": [ {"name": "apiKey", "value": "{{GOOGLE_API_KEY}}"} ] }, @@ -130,9 +130,9 @@ }, { - "name": "MaxMind", + "name": "MaxMindGeoLocation", "type": "geoLocation", - "driverClass": "bubble.cloud.geoLocation.maxmind.MaxMindDriver", + "driverClass": "bubble.cloud.geoLocation.maxmind.MaxMindGeoLocationDriver", "driverConfig": { "url": "{{#exists MAXMIND_URL}}{{{MAXMIND_URL}}}{{else}}https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&license_key=[[apiKey]]&suffix=tar.gz{{/exists}}", "file": "{{#exists MAXMIND_FILE_REGEX}}{{{MAXMIND_FILE_REGEX}}}{{else}}GeoLite2-City_20[\\d]{6}/GeoLite2-City\\.mmdb{{/exists}}" @@ -143,6 +143,17 @@ "template": true }, + { + "name": "WhoisGeoLocation", + "type": "geoLocation", + "driverClass": "bubble.cloud.geoLocation.whois.WhoisGeoLocationDriver", + "driverConfig": { + "host": null, + "port": null + }, + "template": true + }, + { "name": "GoogleGeoTime", "type": "geoTime", diff --git a/config/activation.json b/config/activation.json index 15f52c80..aebb7191 100644 --- a/config/activation.json +++ b/config/activation.json @@ -169,9 +169,12 @@ // GeoLocation /////////////////////// - // Required for locale and "nearest compute region" auto-detection. Currently only MaxMind is supported + // Required for locale and "nearest compute region" auto-detection. + // Currently only MaxMind and Whois are supported. + + // MaxMind is free, but now requires registration and an API token. // Comment this out if you're not going to use it - "MaxMind": { + "MaxMindGeoLocation": { "config": { // these values work for the free GeoLite database, but you still have to specify an apiKey "url": "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&license_key=[[apiKey]]&suffix=tar.gz", @@ -180,13 +183,28 @@ "credentials": {"apiKey": "your_maxmind_api_key"} }, + // Whois is also free, but less accurate. It's worth a try if you have nothing better. + "WhoisGeoLocation": { + "config": { + // Normally the default 'whois' settings are used. + // If you want to pass `-h` and `-p` to whois to set the host and port + // of another whois server to use, set the config params below + "host": null, + "port": null + // If you're not going to change host/port, you can reduce this + // config object to an empty JSON object {} + }, + "credentials": {}, + "template": true + }, + /////////////////////// // GeoCode /////////////////////// // Required for "nearest compute region" auto-detection. Currently only Google GeoCoder is supported // Comment this out if you're not going to use it - "GoogleGeoCoder": { + "GoogleGeoCode": { "credentials": {"apiKey": "your_google_api_key"} }, diff --git a/utils/abp-parser b/utils/abp-parser index 4627dfbe..50753078 160000 --- a/utils/abp-parser +++ b/utils/abp-parser @@ -1 +1 @@ -Subproject commit 4627dfbec2ccb9fd9e7829b00f6dec44316f2819 +Subproject commit 507530784e203e6b5ba4c0b63b8fa946b352212e diff --git a/utils/cobbzilla-utils b/utils/cobbzilla-utils index 8e75e708..51a4ce4a 160000 --- a/utils/cobbzilla-utils +++ b/utils/cobbzilla-utils @@ -1 +1 @@ -Subproject commit 8e75e7087316977e9ee3a5201ba328e62f184ffa +Subproject commit 51a4ce4a48b44a47bec611354cdd8bf2a17d56ee diff --git a/utils/cobbzilla-wizard b/utils/cobbzilla-wizard index 228fa8d9..8deb7c2f 160000 --- a/utils/cobbzilla-wizard +++ b/utils/cobbzilla-wizard @@ -1 +1 @@ -Subproject commit 228fa8d952790d848d4551a7859766e3f23f74d9 +Subproject commit 8deb7c2f886720eb6f0791083be594b1b41f5814