@@ -4,6 +4,7 @@ import bubble.model.cloud.BubbleNode; | |||
import com.fasterxml.jackson.databind.JsonNode; | |||
import com.warrenstrange.googleauth.GoogleAuthenticator; | |||
import lombok.Getter; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.apache.commons.lang3.RandomUtils; | |||
import org.cobbzilla.util.io.FileUtil; | |||
import org.glassfish.grizzly.http.server.Request; | |||
@@ -24,8 +25,10 @@ import static org.cobbzilla.util.daemon.ZillaRuntime.die; | |||
import static org.cobbzilla.util.io.FileUtil.abs; | |||
import static org.cobbzilla.util.io.StreamUtil.stream2string; | |||
import static org.cobbzilla.util.json.JsonUtil.json; | |||
import static org.cobbzilla.util.network.NetworkUtil.*; | |||
import static org.cobbzilla.wizard.resources.ResourceUtil.invalidEx; | |||
@Slf4j | |||
public class ApiConstants { | |||
@Getter(lazy=true) private static final String bubbleDefaultDomain = initDefaultDomain(); | |||
@@ -172,8 +175,13 @@ public class ApiConstants { | |||
} | |||
public static String getRemoteHost(Request req) { | |||
final String remoteHost = req.getHeader("X-Forwarded-For"); | |||
return remoteHost == null ? req.getRemoteAddr() : remoteHost; | |||
final String xff = req.getHeader("X-Forwarded-For"); | |||
final String remoteHost = xff == null ? req.getRemoteAddr() : xff; | |||
if (isPublicIpv4(remoteHost)) return remoteHost; | |||
final String publicIp = getFirstPublicIpv4(); | |||
if (publicIp != null) return publicIp; | |||
final String externalIp = getExternalIp(); | |||
return isPublicIpv4(externalIp) ? externalIp : remoteHost; | |||
} | |||
public static String getUserAgent(ContainerRequest ctx) { return ctx.getHeaderString(USER_AGENT); } | |||
@@ -1,18 +1,18 @@ | |||
package bubble.dao.account; | |||
import bubble.dao.account.message.AccountMessageDAO; | |||
import bubble.dao.app.*; | |||
import bubble.dao.cloud.AnsibleRoleDAO; | |||
import bubble.dao.cloud.BubbleDomainDAO; | |||
import bubble.dao.cloud.BubbleFootprintDAO; | |||
import bubble.dao.cloud.CloudServiceDAO; | |||
import bubble.dao.device.DeviceDAO; | |||
import bubble.dao.app.*; | |||
import bubble.model.account.*; | |||
import bubble.model.app.*; | |||
import bubble.model.cloud.BubbleDomain; | |||
import bubble.model.cloud.BubbleNode; | |||
import bubble.model.cloud.CloudCredentials; | |||
import bubble.model.cloud.CloudService; | |||
import bubble.model.app.*; | |||
import bubble.server.BubbleConfiguration; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.cobbzilla.wizard.dao.AbstractCRUDDAO; | |||
@@ -25,6 +25,7 @@ import javax.transaction.Transactional; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.concurrent.atomic.AtomicBoolean; | |||
import static bubble.ApiConstants.getRemoteHost; | |||
import static bubble.model.account.AccountTemplate.copyTemplateObjects; | |||
@@ -86,9 +87,10 @@ public class AccountDAO extends AbstractCRUDDAO<Account> { | |||
deviceDAO.ensureSpareDevice(accountUuid, thisNode.getNetwork(), true); | |||
} | |||
// copy drivers, keep map of old uuid to new driver so we can map rules below | |||
if (account.hasParent()) { | |||
daemon(new AccountInitializer(this, account, messageDAO)); | |||
final AccountInitializer init = new AccountInitializer(account, this, messageDAO); | |||
account.setAccountInitializer(init); | |||
daemon(init); | |||
} | |||
return super.postCreate(account, context); | |||
@@ -103,11 +105,53 @@ public class AccountDAO extends AbstractCRUDDAO<Account> { | |||
return super.postUpdate(account, context); | |||
} | |||
public void copyTemplates(Account account) { | |||
public void copyTemplates(Account account, AtomicBoolean ready) { | |||
final String parent = account.getParent(); | |||
final Map<String, RuleDriver> drivers = new HashMap<>(); | |||
final String acct = account.getUuid(); | |||
final Map<String, CloudService> clouds = new HashMap<>(); | |||
copyTemplateObjects(acct, parent, cloudDAO, new AccountTemplate.CopyTemplate<>() { | |||
@Override public CloudService preCreate(CloudService parentEntity, CloudService accountEntity) { | |||
return accountEntity.setDelegated(parentEntity.getUuid()) | |||
.setCredentials(CloudCredentials.delegate(configuration.getThisNode(), configuration)) | |||
.setTemplate(false); | |||
} | |||
@Override public void postCreate(CloudService parentEntity, CloudService accountEntity) { | |||
clouds.put(parentEntity.getUuid(), accountEntity); | |||
} | |||
}); | |||
copyTemplateObjects(acct, parent, footprintDAO); | |||
//noinspection Convert2Diamond -- compilation breaks with <> | |||
copyTemplateObjects(acct, parent, domainDAO, new AccountTemplate.CopyTemplate<BubbleDomain>() { | |||
@Override public BubbleDomain preCreate(BubbleDomain parentEntity, BubbleDomain accountEntity) { | |||
final CloudService publicDns = findDnsCloudService(parentEntity, parentEntity.getPublicDns()); | |||
if (publicDns == null) return null; | |||
return accountEntity | |||
.setDelegated(parentEntity.getUuid()) | |||
.setPublicDns(publicDns.getUuid()); | |||
} | |||
public CloudService findDnsCloudService(BubbleDomain parentEntity, String cloudDnsUuid) { | |||
final CloudService dns = clouds.get(cloudDnsUuid); | |||
if (dns == null) { | |||
log.error("DNS service "+ cloudDnsUuid +" could not be found for domain "+parentEntity.getUuid()); | |||
return null; | |||
} | |||
final CloudService acctPublicDns = cloudDAO.findByAccountAndName(acct, dns.getName()); | |||
if (acctPublicDns == null) { | |||
log.error("DNS service not found under account "+acct+": "+dns.getName()); | |||
return null; | |||
} | |||
return dns; | |||
} | |||
}); | |||
ready.set(true); | |||
copyTemplateObjects(acct, parent, roleDAO); | |||
final Map<String, RuleDriver> drivers = new HashMap<>(); | |||
copyTemplateObjects(acct, parent, driverDAO, new AccountTemplate.CopyTemplate<>() { | |||
@Override public void postCreate(RuleDriver parentEntity, RuleDriver accountEntity) { | |||
drivers.put(parentEntity.getUuid(), accountEntity); | |||
@@ -162,46 +206,6 @@ public class AccountDAO extends AbstractCRUDDAO<Account> { | |||
} | |||
}); | |||
final Map<String, CloudService> clouds = new HashMap<>(); | |||
copyTemplateObjects(acct, parent, cloudDAO, new AccountTemplate.CopyTemplate<>() { | |||
@Override public CloudService preCreate(CloudService parentEntity, CloudService accountEntity) { | |||
return accountEntity.setDelegated(parentEntity.getUuid()) | |||
.setCredentials(CloudCredentials.delegate(configuration.getThisNode(), configuration)) | |||
.setTemplate(false); | |||
} | |||
@Override public void postCreate(CloudService parentEntity, CloudService accountEntity) { | |||
clouds.put(parentEntity.getUuid(), accountEntity); | |||
} | |||
}); | |||
copyTemplateObjects(acct, parent, roleDAO); | |||
copyTemplateObjects(acct, parent, footprintDAO); | |||
//noinspection Convert2Diamond -- compilation breaks with <> | |||
copyTemplateObjects(acct, parent, domainDAO, new AccountTemplate.CopyTemplate<BubbleDomain>() { | |||
@Override public BubbleDomain preCreate(BubbleDomain parentEntity, BubbleDomain accountEntity) { | |||
final CloudService publicDns = findDnsCloudService(parentEntity, parentEntity.getPublicDns()); | |||
if (publicDns == null) return null; | |||
return accountEntity | |||
.setDelegated(parentEntity.getUuid()) | |||
.setPublicDns(publicDns.getUuid()); | |||
} | |||
public CloudService findDnsCloudService(BubbleDomain parentEntity, String cloudDnsUuid) { | |||
final CloudService dns = clouds.get(cloudDnsUuid); | |||
if (dns == null) { | |||
log.error("DNS service "+ cloudDnsUuid +" could not be found for domain "+parentEntity.getUuid()); | |||
return null; | |||
} | |||
final CloudService acctPublicDns = cloudDAO.findByAccountAndName(acct, dns.getName()); | |||
if (acctPublicDns == null) { | |||
log.error("DNS service not found under account "+acct+": "+dns.getName()); | |||
return null; | |||
} | |||
return dns; | |||
} | |||
}); | |||
log.info("copyTemplates completed: "+acct); | |||
} | |||
@@ -9,6 +9,8 @@ import bubble.model.account.message.ActionTarget; | |||
import lombok.AllArgsConstructor; | |||
import lombok.extern.slf4j.Slf4j; | |||
import java.util.concurrent.atomic.AtomicBoolean; | |||
import static java.util.concurrent.TimeUnit.SECONDS; | |||
import static org.cobbzilla.util.daemon.ZillaRuntime.die; | |||
import static org.cobbzilla.util.system.Sleep.sleep; | |||
@@ -17,11 +19,20 @@ import static org.cobbzilla.util.system.Sleep.sleep; | |||
public class AccountInitializer implements Runnable { | |||
public static final int MAX_ACCOUNT_INIT_RETRIES = 3; | |||
public static final long COPY_WAIT_TIME = SECONDS.toMillis(3); | |||
public static final long COPY_WAIT_TIME = SECONDS.toMillis(2); | |||
private AccountDAO accountDAO; | |||
private Account account; | |||
private AccountDAO accountDAO; | |||
private AccountMessageDAO messageDAO; | |||
private AtomicBoolean ready = new AtomicBoolean(false); | |||
public AccountInitializer(Account account, AccountDAO accountDAO, AccountMessageDAO messageDAO) { | |||
this.account = account; | |||
this.accountDAO = accountDAO; | |||
this.messageDAO = messageDAO; | |||
} | |||
public boolean ready() { return ready.get(); } | |||
@Override public void run() { | |||
try { | |||
@@ -30,7 +41,7 @@ public class AccountInitializer implements Runnable { | |||
for (int i=0; i<MAX_ACCOUNT_INIT_RETRIES; i++) { | |||
try { | |||
sleep(COPY_WAIT_TIME, "waiting before copyTemplates"); | |||
accountDAO.copyTemplates(account); | |||
accountDAO.copyTemplates(account, ready); | |||
if (account.hasPolicy() && account.getPolicy().hasAccountContacts()) { | |||
messageDAO.sendVerifyRequest(account.getRemoteHost(), account, account.getPolicy().getAccountContacts()[0]); | |||
@@ -1,5 +1,6 @@ | |||
package bubble.model.account; | |||
import bubble.dao.account.AccountInitializer; | |||
import bubble.model.app.AppData; | |||
import bubble.model.app.BubbleApp; | |||
import bubble.model.cloud.*; | |||
@@ -10,6 +11,7 @@ import lombok.Getter; | |||
import lombok.NoArgsConstructor; | |||
import lombok.Setter; | |||
import lombok.experimental.Accessors; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.cobbzilla.util.collection.ArrayUtil; | |||
import org.cobbzilla.wizard.filters.auth.TokenPrincipal; | |||
import org.cobbzilla.wizard.model.HashedPassword; | |||
@@ -28,9 +30,15 @@ import javax.validation.constraints.Size; | |||
import java.util.Arrays; | |||
import java.util.List; | |||
import static java.util.concurrent.TimeUnit.MILLISECONDS; | |||
import static java.util.concurrent.TimeUnit.SECONDS; | |||
import static org.cobbzilla.util.daemon.ZillaRuntime.now; | |||
import static org.cobbzilla.util.reflect.ReflectionUtil.copy; | |||
import static org.cobbzilla.util.system.Sleep.sleep; | |||
import static org.cobbzilla.util.time.TimeUtil.formatDuration; | |||
import static org.cobbzilla.wizard.model.crypto.EncryptedTypes.ENCRYPTED_STRING; | |||
import static org.cobbzilla.wizard.model.crypto.EncryptedTypes.ENC_PAD; | |||
import static org.cobbzilla.wizard.resources.ResourceUtil.invalidEx; | |||
@ECType(root=true) @ECTypeURIs(listFields={"name", "url", "description", "admin", "suspended"}, isDeleteDefined=false) | |||
@ECTypeFields(list={"name", "url", "description", "admin", "suspended"}) | |||
@@ -45,7 +53,7 @@ import static org.cobbzilla.wizard.model.crypto.EncryptedTypes.ENC_PAD; | |||
@ECTypeChild(type=BubbleNode.class, backref="account"), | |||
@ECTypeChild(type=SentNotification.class, backref="account") | |||
}) | |||
@Entity @NoArgsConstructor @Accessors(chain=true) | |||
@Entity @NoArgsConstructor @Accessors(chain=true) @Slf4j | |||
public class Account extends IdentifiableBase implements TokenPrincipal { | |||
public static final String[] UPDATE_FIELDS = {"url", "description", "autoUpdatePolicy"}; | |||
@@ -121,6 +129,28 @@ public class Account extends IdentifiableBase implements TokenPrincipal { | |||
public boolean wantsAppUpdates() { return autoUpdatePolicy != null && autoUpdatePolicy.appUpdates(); } | |||
public boolean wantsDataUpdates() { return autoUpdatePolicy != null && autoUpdatePolicy.dataUpdates(); } | |||
public static final long INIT_WAIT_INTERVAL = MILLISECONDS.toMillis(250); | |||
public static final long INIT_WAIT_TIMEOUT = SECONDS.toMillis(60); | |||
@Transient @JsonIgnore @Getter @Setter private transient AccountInitializer accountInitializer; | |||
public boolean hasAccountInitializer () { return accountInitializer != null; } | |||
public Account waitForAccountInit () { | |||
if (!hasAccountInitializer()) { | |||
log.warn("waitForAccountInit: accountInitializer was not set"); | |||
return this; | |||
} | |||
final long start = now(); | |||
while (!accountInitializer.ready() && now() - start < INIT_WAIT_TIMEOUT) { | |||
sleep(INIT_WAIT_INTERVAL, "postCreate: waiting for AccountInitializer.ready"); | |||
} | |||
if (now() - start > INIT_WAIT_TIMEOUT && !accountInitializer.ready()) { | |||
throw invalidEx("err.accountInit.timeout"); | |||
} | |||
log.info("waitForAccountInit: ready in "+formatDuration(now() - start)); | |||
return this; | |||
} | |||
@Transient @Getter @Setter private transient String apiToken; | |||
@Transient public String getToken() { return getApiToken(); } | |||
@@ -84,7 +84,7 @@ public class AccountsResource { | |||
.setRemoteHost(getRemoteHost(req)) | |||
.setVerifyContact(true); | |||
final Account created = accountDAO.newAccount(req, reg, parent); | |||
return ok(created); | |||
return ok(created.waitForAccountInit()); | |||
} | |||
@GET @Path("/{id}"+EP_DOWNLOAD) | |||
@@ -1,5 +1,6 @@ | |||
package bubble.resources.account; | |||
import bubble.cloud.geoLocation.GeoLocation; | |||
import bubble.dao.SessionDAO; | |||
import bubble.dao.account.AccountDAO; | |||
import bubble.dao.account.AccountPolicyDAO; | |||
@@ -17,12 +18,15 @@ import bubble.service.account.StandardAccountMessageService; | |||
import bubble.service.backup.RestoreService; | |||
import bubble.service.boot.ActivationService; | |||
import bubble.service.boot.SageHelloService; | |||
import bubble.service.cloud.GeoService; | |||
import bubble.service.notify.NotificationService; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.cobbzilla.util.collection.NameAndValue; | |||
import org.cobbzilla.util.string.LocaleUtil; | |||
import org.cobbzilla.wizard.auth.LoginRequest; | |||
import org.cobbzilla.wizard.stream.FileSendableResource; | |||
import org.cobbzilla.wizard.validation.ConstraintViolationBean; | |||
import org.cobbzilla.wizard.validation.SimpleViolationException; | |||
import org.cobbzilla.wizard.validation.ValidationResult; | |||
import org.glassfish.grizzly.http.server.Request; | |||
import org.glassfish.jersey.server.ContainerRequest; | |||
@@ -34,7 +38,9 @@ import javax.ws.rs.*; | |||
import javax.ws.rs.core.Context; | |||
import javax.ws.rs.core.Response; | |||
import java.io.File; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.concurrent.TimeUnit; | |||
import static bubble.ApiConstants.*; | |||
@@ -44,6 +50,7 @@ import static bubble.model.cloud.BubbleNetwork.TAG_PARENT_ACCOUNT; | |||
import static bubble.model.cloud.notify.NotificationType.retrieve_backup; | |||
import static bubble.server.BubbleServer.getRestoreKey; | |||
import static java.util.concurrent.TimeUnit.SECONDS; | |||
import static org.apache.http.HttpHeaders.ACCEPT_LANGUAGE; | |||
import static org.cobbzilla.util.daemon.ZillaRuntime.empty; | |||
import static org.cobbzilla.util.daemon.ZillaRuntime.now; | |||
import static org.cobbzilla.util.http.HttpContentTypes.APPLICATION_JSON; | |||
@@ -66,6 +73,7 @@ public class AuthResource { | |||
@Autowired private AccountMessageDAO accountMessageDAO; | |||
@Autowired private StandardAccountMessageService messageService; | |||
@Autowired private BubbleNodeDAO nodeDAO; | |||
@Autowired private GeoService geoService; | |||
@Autowired private BubbleConfiguration configuration; | |||
@GET @Path(EP_CONFIGS) | |||
@@ -181,7 +189,7 @@ public class AuthResource { | |||
if (parent == null) return invalid("err.parent.notFound", "Parent account does not exist: "+parentUuid); | |||
final Account account = accountDAO.newAccount(req, request, parent); | |||
return ok(account.setToken(sessionDAO.create(account))); | |||
return ok(account.waitForAccountInit().setToken(sessionDAO.create(account))); | |||
} | |||
@POST @Path(EP_LOGIN) | |||
@@ -342,4 +350,46 @@ public class AuthResource { | |||
return ok_empty(); | |||
} | |||
@GET @Path("/detect/locale") | |||
public Response detectLocale(@Context Request req, | |||
@Context ContainerRequest ctx) { | |||
final Map<String, String> locales = new HashMap<>(); | |||
final String langHeader = normalizeLangHeader(req); | |||
if (langHeader != null) locales.put(ACCEPT_LANGUAGE, langHeader); | |||
final String remoteHost = getRemoteHost(req); | |||
try { | |||
final Account caller = userPrincipal(ctx); | |||
final GeoLocation loc = geoService.locate(caller.getUuid(), remoteHost); | |||
if (loc != null) { | |||
final List<String> found = LocaleUtil.getDefaultLocales(loc.getCountry()); | |||
for (int i=0; i<found.size(); i++) { | |||
locales.put("geolocation_"+i, found.get(i)); | |||
} | |||
} | |||
} catch (SimpleViolationException e) { | |||
return invalid(e); | |||
} catch (Exception e) { | |||
log.warn("detectLocale: "+e); | |||
} | |||
return ok(locales.values()); | |||
} | |||
@GET @Path("/detect/timezone") | |||
public Response detectTimezone(@Context Request req, | |||
@Context ContainerRequest ctx) { | |||
final String remoteHost = getRemoteHost(req); | |||
try { | |||
return ok(geoService.getTimeZone(optionalUserPrincipal(ctx), remoteHost)); | |||
} catch (SimpleViolationException e) { | |||
return invalid(e); | |||
} catch (Exception e) { | |||
return invalid("err.timezone.unknown", e.getMessage()); | |||
} | |||
} | |||
} |
@@ -1,6 +1,5 @@ | |||
package bubble.resources.account; | |||
import bubble.cloud.geoLocation.GeoLocation; | |||
import bubble.dao.SessionDAO; | |||
import bubble.dao.account.AccountDAO; | |||
import bubble.dao.account.AccountPolicyDAO; | |||
@@ -20,11 +19,9 @@ import bubble.resources.notify.SentNotificationsResource; | |||
import bubble.server.BubbleConfiguration; | |||
import bubble.service.account.StandardAccountMessageService; | |||
import bubble.service.account.download.AccountDownloadService; | |||
import bubble.service.cloud.GeoService; | |||
import com.fasterxml.jackson.databind.JsonNode; | |||
import lombok.Cleanup; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.cobbzilla.util.string.LocaleUtil; | |||
import org.cobbzilla.wizard.auth.ChangePasswordRequest; | |||
import org.cobbzilla.wizard.client.ApiClientBase; | |||
import org.cobbzilla.wizard.client.script.ApiRunner; | |||
@@ -41,12 +38,8 @@ import javax.ws.rs.*; | |||
import javax.ws.rs.core.Context; | |||
import javax.ws.rs.core.Response; | |||
import java.io.StringWriter; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import static bubble.ApiConstants.*; | |||
import static org.apache.http.HttpHeaders.ACCEPT_LANGUAGE; | |||
import static org.cobbzilla.util.daemon.ZillaRuntime.errorString; | |||
import static org.cobbzilla.util.http.HttpContentTypes.APPLICATION_JSON; | |||
import static org.cobbzilla.util.http.HttpContentTypes.TEXT_PLAIN; | |||
@@ -62,7 +55,6 @@ public class MeResource { | |||
@Autowired private AccountDAO accountDAO; | |||
@Autowired private AccountPolicyDAO policyDAO; | |||
@Autowired private SessionDAO sessionDAO; | |||
@Autowired private GeoService geoService; | |||
@Autowired private AccountDownloadService downloadService; | |||
@Autowired private BubbleConfiguration configuration; | |||
@@ -76,41 +68,6 @@ public class MeResource { | |||
} | |||
} | |||
@GET @Path("/detect/locale") | |||
public Response detectLocale(@Context Request req, | |||
@Context ContainerRequest ctx) { | |||
final Map<String, String> locales = new HashMap<>(); | |||
final String langHeader = normalizeLangHeader(req); | |||
if (langHeader != null) locales.put(ACCEPT_LANGUAGE, langHeader); | |||
final String remoteHost = getRemoteHost(req); | |||
try { | |||
final Account caller = userPrincipal(ctx); | |||
final GeoLocation loc = geoService.locate(caller.getUuid(), remoteHost); | |||
if (loc != null) { | |||
final List<String> found = LocaleUtil.getDefaultLocales(loc.getCountry()); | |||
for (int i=0; i<found.size(); i++) { | |||
locales.put("geolocation_"+i, found.get(i)); | |||
} | |||
} | |||
} catch (Exception e) { | |||
log.warn("detectLocale: "+e); | |||
} | |||
return ok(locales); | |||
} | |||
@GET @Path("/detect/timezone") | |||
public Response detectTimezone(@Context Request req, | |||
@Context ContainerRequest ctx) { | |||
final String remoteHost = getRemoteHost(req); | |||
try { | |||
return ok(geoService.getTimeZone(userPrincipal(ctx), remoteHost)); | |||
} catch (Exception e) { | |||
return invalid("err.timezone.unknown", e.getMessage()); | |||
} | |||
} | |||
@POST @Path(EP_CHANGE_PASSWORD) | |||
public Response changePassword(@Context ContainerRequest ctx, | |||
ChangePasswordRequest request) { | |||
@@ -13,13 +13,12 @@ import bubble.model.cloud.notify.ReceivedNotification; | |||
import bubble.model.cloud.notify.SentNotification; | |||
import bubble.notify.storage.StorageStreamRequest; | |||
import bubble.server.BubbleConfiguration; | |||
import bubble.service.notify.NotificationService; | |||
import bubble.service.backup.RestoreService; | |||
import bubble.service.cloud.StorageStreamService; | |||
import bubble.service.notify.NotificationService; | |||
import com.fasterxml.jackson.databind.JsonNode; | |||
import lombok.Getter; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.cobbzilla.util.network.NetworkUtil; | |||
import org.cobbzilla.util.security.RsaMessage; | |||
import org.cobbzilla.util.string.StringUtil; | |||
import org.glassfish.grizzly.http.server.Request; | |||
@@ -42,6 +41,8 @@ import static org.cobbzilla.util.daemon.ZillaRuntime.empty; | |||
import static org.cobbzilla.util.http.HttpContentTypes.APPLICATION_JSON; | |||
import static org.cobbzilla.util.http.HttpContentTypes.APPLICATION_OCTET_STREAM; | |||
import static org.cobbzilla.util.json.JsonUtil.json; | |||
import static org.cobbzilla.util.network.NetworkUtil.configuredIpsAndExternalIp; | |||
import static org.cobbzilla.util.network.NetworkUtil.isLocalHost; | |||
import static org.cobbzilla.util.string.StringUtil.truncate; | |||
import static org.cobbzilla.util.time.TimeUtil.formatDuration; | |||
import static org.cobbzilla.wizard.resources.ResourceUtil.*; | |||
@@ -61,7 +62,7 @@ public class InboundNotifyResource { | |||
@Autowired private StorageStreamService storageStreamService; | |||
@Autowired private RestoreService restoreService; | |||
@Getter(lazy=true) private final Set<String> localIps = NetworkUtil.configuredIps(); | |||
@Getter(lazy=true) private final Set<String> localIps = configuredIpsAndExternalIp(); | |||
@POST | |||
public Response receiveNotification(@Context Request req, | |||
@@ -150,7 +151,7 @@ public class InboundNotifyResource { | |||
if (fromKey != null) { | |||
if (!fromKey.getRemoteHost().equals(remoteHost)) { | |||
// if request is from 127.0.0.1, check to see if fromKey is for a local address | |||
if (remoteHost.equals("127.0.0.1") && getLocalIps().contains(fromKey.getRemoteHost())) { | |||
if (isLocalHost(remoteHost) && getLocalIps().contains(fromKey.getRemoteHost())) { | |||
log.debug("findFromKey: request from 127.0.0.1 is OK, key is local: "+fromKey.getRemoteHost()+ " (ips="+ StringUtil.toString(getLocalIps())+")"); | |||
} else { | |||
log.warn("findFromKey: remoteHost for for node " + fromNodeUuid + " (key=" + fromKeyUuid + ", remoteHost=" + fromKey.getRemoteHost() + ") does not match request: " + remoteHost+ " (ips="+ StringUtil.toString(getLocalIps())+")"); | |||
@@ -8,6 +8,7 @@ import bubble.cloud.geoCode.GeoCodeResult; | |||
import bubble.cloud.geoCode.GeoCodeServiceDriver; | |||
import bubble.cloud.geoLocation.GeoLocation; | |||
import bubble.cloud.geoTime.GeoTimeZone; | |||
import bubble.dao.account.AccountDAO; | |||
import bubble.dao.cloud.BubbleFootprintDAO; | |||
import bubble.dao.cloud.CloudServiceDAO; | |||
import bubble.model.account.Account; | |||
@@ -37,6 +38,7 @@ public class GeoService { | |||
// todo: move to config? | |||
public static final int LOC_MAX_DISTANCE = 50000; | |||
@Autowired private AccountDAO accountDAO; | |||
@Autowired private CloudServiceDAO cloudDAO; | |||
@Autowired private BubbleFootprintDAO footprintDAO; | |||
@Autowired private BubbleConfiguration configuration; | |||
@@ -112,6 +114,7 @@ public class GeoService { | |||
public GeoTimeZone getTimeZone (Account account, String ip) { | |||
if (account == null) account = accountDAO.findFirstAdmin(); | |||
final List<CloudService> geoServices = cloudDAO.findByAccountAndType(account.getUuid(), CloudServiceType.geoTime); | |||
if (geoServices.isEmpty()) throw new SimpleViolationException("err.geoTimeService.notFound"); | |||
geoServices.sort(SORT_PRIORITY); | |||
@@ -26,6 +26,7 @@ err.phone.invalid=SMS Phone is invalid | |||
err.phone.length=SMS Phone is too long | |||
err.country.invalid=Country is invalid | |||
err.parent.notFound=Parent account does not exist | |||
err.accountInit.timeout=Timeout initializing new account | |||
# Login/Registration form | |||
form_label_title_login=Login | |||
@@ -1 +1 @@ | |||
Subproject commit b500db5e9c4a0e621833e788dc4e6cf5fae5e2ee | |||
Subproject commit 0cf7321e714801118c7ab13ca2202a68936c0dea |
@@ -1 +1 @@ | |||
Subproject commit 862c6282b7ecdf9b1146f4ecb005cf38be1c4e86 | |||
Subproject commit 51b557f242ea52ed339ac6469adbc42b8873a3e9 |
@@ -1 +1 @@ | |||
Subproject commit 86a153ecc2531008afab4e3bfed471f9d957dab7 | |||
Subproject commit 54c08985284f4f81dad3200b04e93384cbdffb12 |