Explorar el Código

add whois geo location and scrub codebase for safe shell args

tags/v1.5.4
Jonathan Cobb hace 4 años
padre
commit
ea390d85e7
Se han modificado 25 ficheros con 462 adiciones y 54 borrados
  1. +1
    -1
      bin/first_time_ubuntu.sh
  2. +2
    -4
      bubble-server/src/main/java/bubble/app/bblock/BubbleBlockAppConfigDriver.java
  3. +12
    -0
      bubble-server/src/main/java/bubble/cloud/CloudRegionRelative.java
  4. +13
    -6
      bubble-server/src/main/java/bubble/cloud/dns/DnsServiceDriver.java
  5. +17
    -3
      bubble-server/src/main/java/bubble/cloud/geoLocation/GeoLocateServiceDriverBase.java
  6. +6
    -0
      bubble-server/src/main/java/bubble/cloud/geoLocation/GeoLocation.java
  7. +1
    -1
      bubble-server/src/main/java/bubble/cloud/geoLocation/maxmind/MaxMindGeoLocationDriver.java
  8. +16
    -0
      bubble-server/src/main/java/bubble/cloud/geoLocation/whois/WhoisConfig.java
  9. +71
    -0
      bubble-server/src/main/java/bubble/cloud/geoLocation/whois/WhoisGeoLocationDriver.java
  10. +5
    -4
      bubble-server/src/main/java/bubble/main/RekeyDatabaseMain.java
  11. +17
    -9
      bubble-server/src/main/java/bubble/model/cloud/RegionalServiceDriver.java
  12. +1
    -1
      bubble-server/src/main/java/bubble/resources/bill/AccountPlansResource.java
  13. +3
    -1
      bubble-server/src/main/java/bubble/resources/cloud/CloudServiceRegionsResource.java
  14. +5
    -1
      bubble-server/src/main/java/bubble/resources/cloud/NetworksResource.java
  15. +2
    -3
      bubble-server/src/main/java/bubble/rule/bblock/BubbleBlockRuleDriver.java
  16. +2
    -2
      bubble-server/src/main/java/bubble/server/BubbleServer.java
  17. +0
    -7
      bubble-server/src/main/java/bubble/service/boot/PublicUpgradeMonitorService.java
  18. +2
    -1
      bubble-server/src/main/java/bubble/service/cloud/StandardNetworkService.java
  19. +2
    -1
      bubble-server/src/main/java/bubble/service/packer/PackerService.java
  20. +246
    -0
      bubble-server/src/main/resources/bubble/cloud/geoLocation/country-locations.json
  21. +14
    -3
      bubble-server/src/main/resources/models/defaults/cloudService.json
  22. +21
    -3
      config/activation.json
  23. +1
    -1
      utils/abp-parser
  24. +1
    -1
      utils/cobbzilla-utils
  25. +1
    -1
      utils/cobbzilla-wizard

+ 1
- 1
bin/first_time_ubuntu.sh Ver fichero

@@ -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


+ 2
- 4
bubble-server/src/main/java/bubble/app/bblock/BubbleBlockAppConfigDriver.java Ver fichero

@@ -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");
}



+ 12
- 0
bubble-server/src/main/java/bubble/cloud/CloudRegionRelative.java Ver fichero

@@ -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<CloudRegionRelative> {
@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());
}
}

}

+ 13
- 6
bubble-server/src/main/java/bubble/cloud/dns/DnsServiceDriver.java Ver fichero

@@ -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<DnsRecord> dig(String host, DnsType type, String name) { return dig(host, 53, type, name); }

static Collection<DnsRecord> 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<DnsRecord> records = new ArrayList<>();
for (String line : output.split("[\n]+")) {


+ 17
- 3
bubble-server/src/main/java/bubble/cloud/geoLocation/GeoLocateServiceDriverBase.java Ver fichero

@@ -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<T> extends CloudServiceDriverBase<T> 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<T> extends CloudServiceDriverBa
@Autowired private RedisService redis;
@Getter(lazy=true) private final RedisService cache = redis.prefixNamespace(getClass().getName()+"_cache_");

@Getter(lazy=true) private final Map<String, GeoLocation> countryMap = initCountryMap();
private Map<String, GeoLocation> 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<T> extends CloudServiceDriverBa
final String urlWithLicense = HandlebarsUtil.apply(getHandlebars(), url, getCredentials().newContext(), '[', ']')
.replace("&amp;", "&");
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;


+ 6
- 0
bubble-server/src/main/java/bubble/cloud/geoLocation/GeoLocation.java Ver fichero

@@ -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); }



bubble-server/src/main/java/bubble/cloud/geoLocation/maxmind/MaxMindDriver.java → bubble-server/src/main/java/bubble/cloud/geoLocation/maxmind/MaxMindGeoLocationDriver.java Ver fichero

@@ -16,7 +16,7 @@ import java.net.InetAddress;

import static org.cobbzilla.util.daemon.ZillaRuntime.die;

public class MaxMindDriver extends GeoLocateServiceDriverBase<CloudApiUrlConfig> {
public class MaxMindGeoLocationDriver extends GeoLocateServiceDriverBase<CloudApiUrlConfig> {

private DatabaseReader reader;


+ 16
- 0
bubble-server/src/main/java/bubble/cloud/geoLocation/whois/WhoisConfig.java Ver fichero

@@ -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; }

}

+ 71
- 0
bubble-server/src/main/java/bubble/cloud/geoLocation/whois/WhoisGeoLocationDriver.java Ver fichero

@@ -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<WhoisConfig> {

@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<String> 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;
}
}

}

+ 5
- 4
bubble-server/src/main/java/bubble/main/RekeyDatabaseMain.java Ver fichero

@@ -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<RekeyDatabaseOptions> {

@@ -93,13 +94,13 @@ public class RekeyDatabaseMain extends BaseMain<RekeyDatabaseOptions> {
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());



+ 17
- 9
bubble-server/src/main/java/bubble/model/cloud/RegionalServiceDriver.java Ver fichero

@@ -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<CloudRegionRelative> allRegions,
CloudService c,
CloudRegion region) {
final CloudRegionRelative r = new CloudRegionRelative(region);
r.setDistance(0);
r.setCloud(c.getUuid());
allRegions.add(r);
}

List<CloudRegion> getRegions();

default List<CloudRegion> getRegions(BubbleFootprint footprint) {


+ 1
- 1
bubble-server/src/main/java/bubble/resources/bill/AccountPlansResource.java Ver fichero

@@ -172,7 +172,7 @@ public class AccountPlansResource extends AccountOwnedResource<AccountPlan, Acco
request.setDomain(domain.getUuid());

} else {
if (!validateRegexMatches(HOST_PATTERN, forkHost)) {
if (!isHostname(forkHost)) {
errors.addViolation("err.forkHost.invalid");
} else if (domain != null && !forkHost.endsWith("." + domain.getName())) {
final BubbleDomain foundDomain = domainDAO.findByAccount(caller.getUuid()).stream()


+ 3
- 1
bubble-server/src/main/java/bubble/resources/cloud/CloudServiceRegionsResource.java Ver fichero

@@ -108,7 +108,9 @@ public class CloudServiceRegionsResource {
if (footprint == null) return notFound(footprintId);
}

return ok(findClosestRegions(configuration, computeClouds(), footprint, loc.getLatitude(), loc.getLongitude(), null, geoService.supportsGeoLocation()));
return ok(findClosestRegions(configuration, computeClouds(), footprint,
loc.getLatitude(), loc.getLongitude(),
null, geoService.supportsGeoLocation()));
}

public List<CloudRegion> findRegions(List<CloudService> clouds, BubbleFootprint footprint) {


+ 5
- 1
bubble-server/src/main/java/bubble/resources/cloud/NetworksResource.java Ver fichero

@@ -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<BubbleNetwork, Bubble
} catch (Exception e) {
return invalid("err.latlon.invalid", "lat/lon was invalid: "+e.getMessage(), lat+","+lon);
}
if (latitude < 0 || longitude < 0) return invalid("err.latlon.invalid");
} else {
// try to figure it out from the IP
final String remoteHost = getRemoteHost(req);


+ 2
- 3
bubble-server/src/main/java/bubble/rule/bblock/BubbleBlockRuleDriver.java Ver fichero

@@ -46,8 +46,7 @@ import static org.cobbzilla.util.json.JsonUtil.COMPACT_MAPPER;
import static org.cobbzilla.util.json.JsonUtil.json;
import static org.cobbzilla.util.string.StringUtil.EMPTY;
import static org.cobbzilla.util.string.StringUtil.getPackagePath;
import static org.cobbzilla.util.string.ValidationRegexes.HOST_PATTERN;
import static org.cobbzilla.util.string.ValidationRegexes.validateRegexMatches;
import static org.cobbzilla.util.string.ValidationRegexes.*;
import static org.cobbzilla.wizard.resources.ResourceUtil.invalidEx;

@Slf4j
@@ -504,7 +503,7 @@ public class BubbleBlockRuleDriver extends TrafficAnalyticsRuleDriver
if (data.getKey().startsWith(PREFIX_APPDATA_SHOW_STATS)) {
final DeviceService deviceService = configuration.getBean(DeviceService.class);
final String fqdn = fqdnFromKey(data.getKey());
if (validateRegexMatches(HOST_PATTERN, fqdn)) {
if (isHostname(fqdn)) {
if (data.deleting()) {
if (log.isInfoEnabled()) log.info(prefix+"unsetting fqdn: "+fqdn);
deviceService.unsetBlockStatsForFqdn(account, fqdn);


+ 2
- 2
bubble-server/src/main/java/bubble/server/BubbleServer.java Ver fichero

@@ -10,7 +10,6 @@ import bubble.server.listener.NodeInitializerListener;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.cobbzilla.util.io.FileUtil;
import org.cobbzilla.util.system.CommandShell;
import org.cobbzilla.wizard.server.RestServer;
import org.cobbzilla.wizard.server.RestServerBase;
import org.cobbzilla.wizard.server.RestServerLifecycleListener;
@@ -39,6 +38,7 @@ import static org.cobbzilla.util.io.FileUtil.abs;
import static org.cobbzilla.util.json.JsonUtil.json;
import static org.cobbzilla.util.network.NetworkUtil.IPv4_ALL_ADDRS;
import static org.cobbzilla.util.network.NetworkUtil.IPv4_LOCALHOST;
import static org.cobbzilla.util.system.CommandShell.loadShellExports;
import static org.cobbzilla.util.system.OutOfMemoryErrorUncaughtExceptionHandler.EXIT_ON_OOME;

@NoArgsConstructor @Slf4j
@@ -126,7 +126,7 @@ public class BubbleServer extends RestServerBase<BubbleConfiguration> {
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);
}


+ 0
- 7
bubble-server/src/main/java/bubble/service/boot/PublicUpgradeMonitorService.java Ver fichero

@@ -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


+ 2
- 1
bubble-server/src/main/java/bubble/service/cloud/StandardNetworkService.java Ver fichero

@@ -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();


+ 2
- 1
bubble-server/src/main/java/bubble/service/packer/PackerService.java Ver fichero

@@ -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;


+ 246
- 0
bubble-server/src/main/resources/bubble/cloud/geoLocation/country-locations.json Ver fichero

@@ -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}
]

+ 14
- 3
bubble-server/src/main/resources/models/defaults/cloudService.json Ver fichero

@@ -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",


+ 21
- 3
config/activation.json Ver fichero

@@ -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"}
},



+ 1
- 1
utils/abp-parser

@@ -1 +1 @@
Subproject commit 4627dfbec2ccb9fd9e7829b00f6dec44316f2819
Subproject commit 507530784e203e6b5ba4c0b63b8fa946b352212e

+ 1
- 1
utils/cobbzilla-utils

@@ -1 +1 @@
Subproject commit 8e75e7087316977e9ee3a5201ba328e62f184ffa
Subproject commit 51a4ce4a48b44a47bec611354cdd8bf2a17d56ee

+ 1
- 1
utils/cobbzilla-wizard

@@ -1 +1 @@
Subproject commit 228fa8d952790d848d4551a7859766e3f23f74d9
Subproject commit 8deb7c2f886720eb6f0791083be594b1b41f5814

Cargando…
Cancelar
Guardar