@@ -176,6 +176,7 @@ public class ApiConstants { | |||
public static final String EP_NODES = "/nodes"; | |||
public static final String EP_DEVICES = "/devices"; | |||
public static final String EP_DEVICE_TYPES = "/deviceTypes"; | |||
public static final String EP_FLEX_ROUTERS = "/flexRouters"; | |||
public static final String EP_MODEL = "/model"; | |||
public static final String EP_VPN = "/vpn"; | |||
public static final String EP_IPS = "/ips"; | |||
@@ -276,8 +277,7 @@ public class ApiConstants { | |||
} | |||
public static String getRemoteHost(Request req) { | |||
final String xff = req.getHeader("X-Forwarded-For"); | |||
final String remoteHost = xff == null ? req.getRemoteAddr() : xff; | |||
final String remoteHost = getRemoteAddr(req); | |||
if (isPublicIpv4(remoteHost)) return remoteHost; | |||
final String publicIp = getFirstPublicIpv4(); | |||
if (publicIp != null) return publicIp; | |||
@@ -285,6 +285,11 @@ public class ApiConstants { | |||
return isPublicIpv4(externalIp) ? externalIp : remoteHost; | |||
} | |||
public static String getRemoteAddr(Request req) { | |||
final String xff = req.getHeader("X-Forwarded-For"); | |||
return xff == null ? req.getRemoteAddr() : xff; | |||
} | |||
public static String getUserAgent(ContainerRequest ctx) { return ctx.getHeaderString(USER_AGENT); } | |||
public static String getReferer(ContainerRequest ctx) { return ctx.getHeaderString(REFERER); } | |||
@@ -23,7 +23,7 @@ import bubble.server.BubbleConfiguration; | |||
import bubble.service.SearchService; | |||
import bubble.service.account.SyncPasswordService; | |||
import bubble.service.boot.SelfNodeService; | |||
import bubble.service.cloud.DeviceIdService; | |||
import bubble.service.device.DeviceService; | |||
import bubble.service.stream.RuleEngineService; | |||
import lombok.Getter; | |||
import lombok.NonNull; | |||
@@ -78,7 +78,7 @@ public class AccountDAO extends AbstractCRUDDAO<Account> implements SqlViewSearc | |||
@Autowired private SearchService searchService; | |||
@Autowired private SyncPasswordService syncPasswordService; | |||
@Autowired private ReferralCodeDAO referralCodeDAO; | |||
@Autowired private DeviceIdService deviceService; | |||
@Autowired private DeviceService deviceService; | |||
@Autowired private RuleEngineService ruleEngineService; | |||
public Account newAccount(Request req, Account caller, AccountRegistration request, Account parent) { | |||
@@ -5,7 +5,7 @@ | |||
package bubble.dao.app; | |||
import bubble.model.app.AppSite; | |||
import bubble.service.cloud.DeviceIdService; | |||
import bubble.service.device.DeviceService; | |||
import bubble.service.stream.RuleEngineService; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
import org.springframework.stereotype.Repository; | |||
@@ -14,7 +14,7 @@ import org.springframework.stereotype.Repository; | |||
public class AppSiteDAO extends AppTemplateEntityDAO<AppSite> { | |||
@Autowired private RuleEngineService ruleEngineService; | |||
@Autowired private DeviceIdService deviceService; | |||
@Autowired private DeviceService deviceService; | |||
@Override public AppSite postCreate(AppSite site, Object context) { | |||
// todo: update entities based on this template if account has updates enabled | |||
@@ -11,7 +11,7 @@ import bubble.dao.app.AppDataDAO; | |||
import bubble.model.device.BubbleDeviceType; | |||
import bubble.model.device.Device; | |||
import bubble.server.BubbleConfiguration; | |||
import bubble.service.cloud.DeviceIdService; | |||
import bubble.service.device.DeviceService; | |||
import lombok.NonNull; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.hibernate.criterion.Order; | |||
@@ -46,7 +46,7 @@ public class DeviceDAO extends AccountOwnedEntityDAO<Device> { | |||
@Autowired private BubbleConfiguration configuration; | |||
@Autowired private AppDataDAO dataDAO; | |||
@Autowired private TrustedClientDAO trustDAO; | |||
@Autowired private DeviceIdService deviceIdService; | |||
@Autowired private DeviceService deviceService; | |||
@Override public Order getDefaultSortOrder() { return ORDER_CTIME_ASC; } | |||
@@ -113,7 +113,7 @@ public class DeviceDAO extends AccountOwnedEntityDAO<Device> { | |||
result = super.update(uninitialized); | |||
} | |||
deviceIdService.setDeviceSecurityLevel(result); | |||
deviceService.setDeviceSecurityLevel(result); | |||
return result; | |||
} | |||
} | |||
@@ -125,7 +125,7 @@ public class DeviceDAO extends AccountOwnedEntityDAO<Device> { | |||
toUpdate.update(updateRequest); | |||
final var updated = super.update(toUpdate); | |||
deviceIdService.setDeviceSecurityLevel(updated); | |||
deviceService.setDeviceSecurityLevel(updated); | |||
refreshVpnUsers(); | |||
return updated; | |||
} | |||
@@ -0,0 +1,21 @@ | |||
package bubble.dao.device; | |||
import bubble.dao.account.AccountOwnedEntityDAO; | |||
import bubble.model.device.FlexRouter; | |||
import org.springframework.stereotype.Repository; | |||
import java.util.List; | |||
import static org.hibernate.criterion.Restrictions.*; | |||
@Repository | |||
public class FlexRouterDAO extends AccountOwnedEntityDAO<FlexRouter> { | |||
public List<FlexRouter> findEnabledAndRegistered() { | |||
return list(criteria().add(and( | |||
eq("enabled", true), | |||
ne("port", 0), | |||
isNotNull("token")))); | |||
} | |||
} |
@@ -0,0 +1,84 @@ | |||
package bubble.model.device; | |||
import bubble.model.account.Account; | |||
import bubble.model.account.HasAccountNoName; | |||
import com.fasterxml.jackson.annotation.JsonIgnore; | |||
import lombok.Getter; | |||
import lombok.NoArgsConstructor; | |||
import lombok.Setter; | |||
import lombok.ToString; | |||
import lombok.experimental.Accessors; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.apache.commons.collections.map.SingletonMap; | |||
import org.cobbzilla.wizard.model.Identifiable; | |||
import org.cobbzilla.wizard.model.IdentifiableBase; | |||
import org.cobbzilla.wizard.model.entityconfig.EntityFieldMode; | |||
import org.cobbzilla.wizard.model.entityconfig.EntityFieldType; | |||
import org.cobbzilla.wizard.model.entityconfig.annotations.*; | |||
import javax.persistence.Column; | |||
import javax.persistence.Entity; | |||
import javax.persistence.Transient; | |||
import static bubble.ApiConstants.EP_FLEX_ROUTERS; | |||
import static org.cobbzilla.util.daemon.ZillaRuntime.*; | |||
import static org.cobbzilla.util.json.JsonUtil.json; | |||
import static org.cobbzilla.util.reflect.ReflectionUtil.copy; | |||
@Entity | |||
@ECType(root=true) @ToString(of={"ip", "port"}) | |||
@ECTypeURIs(baseURI=EP_FLEX_ROUTERS, listFields={"name", "enabled"}) | |||
@NoArgsConstructor @Accessors(chain=true) @Slf4j | |||
@ECIndexes({ @ECIndex(unique=true, of={"account", "ip"}) }) | |||
public class FlexRouter extends IdentifiableBase implements HasAccountNoName { | |||
public static final String[] CREATE_FIELDS = { "ip", "enabled" }; | |||
public static final String[] UPDATE_FIELDS = { "enabled" }; | |||
public FlexRouter (FlexRouter other) { copy(this, other, CREATE_FIELDS); } | |||
@Override public Identifiable update(Identifiable other) { copy(this, other, UPDATE_FIELDS); return this; } | |||
@ECSearchable(filter=true) @ECField(index=10) | |||
@ECIndex @Column(nullable=false, length=500) | |||
@Getter @Setter private String ip; | |||
@ECSearchable(filter=true) @ECField(index=20) | |||
@ECIndex @Column(nullable=false) | |||
@JsonIgnore @Getter @Setter private Integer port = 0; | |||
public String id () { return getIp() + "/" + getUuid(); } | |||
@ECSearchable @ECField(index=30) | |||
@ECForeignKey(entity=Account.class) | |||
@Column(nullable=false, updatable=false, length=UUID_MAXLEN) | |||
@Getter @Setter private String account; | |||
@ECSearchable @ECField(index=40) | |||
@ECIndex @Column(nullable=false) | |||
@Getter @Setter private Boolean enabled = true; | |||
public boolean enabled () { return bool(enabled); } | |||
@ECSearchable @ECField(index=50) | |||
@ECIndex @Column(nullable=false) | |||
@Getter @Setter private Boolean active = true; | |||
public boolean active() { return bool(active); } | |||
@ECSearchable @ECField(index=60, type=EntityFieldType.epoch_time, mode=EntityFieldMode.readOnly) | |||
@Getter @Setter private Long lastSeen; | |||
public FlexRouter setLastSeen () { return setLastSeen(now()); } | |||
@JsonIgnore @Transient public long getAge () { return lastSeen == null ? Long.MAX_VALUE : now() - lastSeen; } | |||
@ECSearchable(filter=true) @ECField(index=70) | |||
@ECIndex @Column(length=100) | |||
@JsonIgnore @Getter @Setter private String token; | |||
public boolean hasToken () { return !empty(token); } | |||
@Transient @Getter @Setter private String serverToken; | |||
public String pingUrl() { return "http://" + getIp() + ":" + getPort() + "/ping"; } | |||
public String pingObject() { return json(new SingletonMap("token", getToken())); } | |||
} |
@@ -19,6 +19,7 @@ import bubble.model.device.BubbleDeviceType; | |||
import bubble.resources.app.AppsResource; | |||
import bubble.resources.bill.*; | |||
import bubble.resources.cloud.*; | |||
import bubble.resources.device.DevicesResource; | |||
import bubble.resources.driver.DriversResource; | |||
import bubble.resources.notify.ReceivedNotificationsResource; | |||
import bubble.resources.notify.SentNotificationsResource; | |||
@@ -32,7 +32,7 @@ import bubble.service.bill.PromotionService; | |||
import bubble.service.boot.ActivationService; | |||
import bubble.service.boot.NodeManagerService; | |||
import bubble.service.boot.SageHelloService; | |||
import bubble.service.cloud.DeviceIdService; | |||
import bubble.service.device.DeviceService; | |||
import bubble.service.cloud.GeoService; | |||
import bubble.service.notify.NotificationService; | |||
import bubble.service.upgrade.BubbleJarUpgradeService; | |||
@@ -97,7 +97,7 @@ public class AuthResource { | |||
@Autowired private BubbleConfiguration configuration; | |||
@Autowired private StandardAuthenticatorService authenticatorService; | |||
@Autowired private PromotionService promoService; | |||
@Autowired private DeviceIdService deviceIdService; | |||
@Autowired private DeviceService deviceService; | |||
@Autowired private DeviceDAO deviceDAO; | |||
@Autowired private BubbleNodeKeyDAO nodeKeyDAO; | |||
@Autowired private NodeManagerService nodeManagerService; | |||
@@ -675,7 +675,7 @@ public class AuthResource { | |||
} else { | |||
final String remoteHost = getRemoteHost(req); | |||
if (!empty(remoteHost)) { | |||
final Device device = deviceIdService.findDeviceByIp(remoteHost); | |||
final Device device = deviceService.findDeviceByIp(remoteHost); | |||
if (device != null) { | |||
type = device.getDeviceType().getCertType(); | |||
} | |||
@@ -19,6 +19,8 @@ import bubble.model.device.BubbleDeviceType; | |||
import bubble.resources.app.AppsResource; | |||
import bubble.resources.bill.*; | |||
import bubble.resources.cloud.*; | |||
import bubble.resources.device.DevicesResource; | |||
import bubble.resources.device.FlexRoutersResource; | |||
import bubble.resources.driver.DriversResource; | |||
import bubble.resources.notify.ReceivedNotificationsResource; | |||
import bubble.resources.notify.SentNotificationsResource; | |||
@@ -371,6 +373,12 @@ public class MeResource { | |||
return ok(BubbleDeviceType.getSelectableTypes()); | |||
} | |||
@Path(EP_FLEX_ROUTERS) | |||
public FlexRoutersResource getFlexRouters(@Context ContainerRequest ctx) { | |||
final Account caller = userPrincipal(ctx); | |||
return configuration.subResource(FlexRoutersResource.class, caller); | |||
} | |||
@Path(EP_REFERRAL_CODES) | |||
public ReferralCodesResource getReferralCodes(@Context ContainerRequest ctx) { | |||
final Account caller = userPrincipal(ctx); | |||
@@ -12,7 +12,7 @@ import bubble.model.app.config.AppDataDriver; | |||
import bubble.model.app.config.AppDataView; | |||
import bubble.model.device.Device; | |||
import bubble.resources.account.AccountOwnedTemplateResource; | |||
import bubble.service.cloud.DeviceIdService; | |||
import bubble.service.device.DeviceService; | |||
import org.cobbzilla.wizard.model.search.SearchQuery; | |||
import org.glassfish.grizzly.http.server.Request; | |||
import org.glassfish.jersey.server.ContainerRequest; | |||
@@ -32,7 +32,7 @@ public class AppSitesResource extends AccountOwnedTemplateResource<AppSite, AppS | |||
private final BubbleApp app; | |||
@Autowired private DeviceIdService deviceIdService; | |||
@Autowired private DeviceService deviceService; | |||
public AppSitesResource(Account account, BubbleApp app) { | |||
super(account); | |||
@@ -102,7 +102,7 @@ public class AppSitesResource extends AccountOwnedTemplateResource<AppSite, AppS | |||
if (view == null) return notFound(viewName); | |||
final String remoteHost = getRemoteHost(req); | |||
final Device device = deviceIdService.findDeviceByIp(remoteHost); | |||
final Device device = deviceService.findDeviceByIp(remoteHost); | |||
final AppDataDriver driver = app.getDataConfig().getDataDriver(configuration); | |||
return ok(driver.query(caller, device, app, site, view, query)); | |||
@@ -9,7 +9,7 @@ import bubble.model.app.BubbleApp; | |||
import bubble.model.app.config.AppDataDriver; | |||
import bubble.model.app.config.AppDataView; | |||
import bubble.model.device.Device; | |||
import bubble.service.cloud.DeviceIdService; | |||
import bubble.service.device.DeviceService; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.cobbzilla.wizard.model.search.SearchQuery; | |||
import org.glassfish.grizzly.http.server.Request; | |||
@@ -29,7 +29,7 @@ public class AppsResource extends AppsResourceBase { | |||
public AppsResource(Account account) { super(account); } | |||
@Autowired private DeviceIdService deviceIdService; | |||
@Autowired private DeviceService deviceService; | |||
@GET @Path("/{id}"+EP_VIEW+"/{view}") | |||
public Response search(@Context Request req, | |||
@@ -58,7 +58,7 @@ public class AppsResource extends AppsResourceBase { | |||
if (view == null) return notFound(viewName); | |||
final String remoteHost = getRemoteHost(req); | |||
final Device device = deviceIdService.findDeviceByIp(remoteHost); | |||
final Device device = deviceService.findDeviceByIp(remoteHost); | |||
final AppDataDriver driver = app.getDataConfig().getDataDriver(configuration); | |||
return ok(driver.query(caller, device, app, null, view, query)); | |||
@@ -2,14 +2,16 @@ | |||
* Copyright (c) 2020 Bubble, Inc. All rights reserved. | |||
* For personal (non-commercial) use, see license: https://getbubblenow.com/bubble-license/ | |||
*/ | |||
package bubble.resources.account; | |||
package bubble.resources.device; | |||
import bubble.dao.device.DeviceDAO; | |||
import bubble.model.account.Account; | |||
import bubble.model.device.Device; | |||
import bubble.model.device.DeviceSecurityLevel; | |||
import bubble.resources.account.AccountOwnedResource; | |||
import bubble.resources.account.VpnConfigResource; | |||
import bubble.server.BubbleConfiguration; | |||
import bubble.service.cloud.DeviceIdService; | |||
import bubble.service.device.DeviceService; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.glassfish.grizzly.http.server.Request; | |||
import org.glassfish.jersey.server.ContainerRequest; | |||
@@ -53,7 +55,7 @@ public class DevicesResource extends AccountOwnedResource<Device, DeviceDAO> { | |||
} | |||
@Override protected Device populate(ContainerRequest ctx, Device device) { | |||
return device.setStatus(deviceIdService.getDeviceStatus(device.getUuid())); | |||
return device.setStatus(deviceService.getDeviceStatus(device.getUuid())); | |||
} | |||
@Override protected List<Device> sort(List<Device> list, Request req, ContainerRequest ctx) { | |||
@@ -106,14 +108,14 @@ public class DevicesResource extends AccountOwnedResource<Device, DeviceDAO> { | |||
return configuration.subResource(VpnConfigResource.class, device); | |||
} | |||
@Autowired private DeviceIdService deviceIdService; | |||
@Autowired private DeviceService deviceService; | |||
@GET @Path("/{id}"+EP_IPS) | |||
public Response getIps(@Context ContainerRequest ctx, | |||
@PathParam("id") String id) { | |||
final Device device = getDao().findByAccountAndId(getAccountUuid(ctx), id); | |||
if (device == null) return notFound(id); | |||
return ok(deviceIdService.findIpsByDevice(device.getUuid())); | |||
return ok(deviceService.findIpsByDevice(device.getUuid())); | |||
} | |||
@GET @Path("/{id}"+EP_STATUS) | |||
@@ -121,7 +123,7 @@ public class DevicesResource extends AccountOwnedResource<Device, DeviceDAO> { | |||
@PathParam("id") String id) { | |||
final Device device = getDao().findByAccountAndId(getAccountUuid(ctx), id); | |||
if (device == null) return notFound(id); | |||
return ok(deviceIdService.getLiveDeviceStatus(device.getUuid())); | |||
return ok(deviceService.getLiveDeviceStatus(device.getUuid())); | |||
} | |||
} |
@@ -0,0 +1,62 @@ | |||
package bubble.resources.device; | |||
import bubble.dao.device.FlexRouterDAO; | |||
import bubble.model.account.Account; | |||
import bubble.model.device.Device; | |||
import bubble.model.device.FlexRouter; | |||
import bubble.resources.account.AccountOwnedResource; | |||
import bubble.service.device.DeviceService; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.glassfish.grizzly.http.server.Request; | |||
import org.glassfish.jersey.server.ContainerRequest; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
import javax.ws.rs.POST; | |||
import javax.ws.rs.Path; | |||
import javax.ws.rs.PathParam; | |||
import javax.ws.rs.core.Context; | |||
import javax.ws.rs.core.Response; | |||
import static bubble.ApiConstants.EP_REGISTER; | |||
import static bubble.ApiConstants.getRemoteAddr; | |||
import static org.apache.commons.lang3.RandomStringUtils.randomAlphanumeric; | |||
import static org.cobbzilla.wizard.resources.ResourceUtil.*; | |||
@Slf4j | |||
public class FlexRoutersResource extends AccountOwnedResource<FlexRouter, FlexRouterDAO> { | |||
@Autowired private DeviceService deviceService; | |||
public FlexRoutersResource(Account account) { super(account); } | |||
@Override protected boolean isReadOnly(ContainerRequest ctx) { | |||
final Account caller = userPrincipal(ctx); | |||
return !caller.admin(); | |||
} | |||
@POST @Path("{id}"+EP_REGISTER) | |||
public Response register(@Context Request req, | |||
@Context ContainerRequest ctx, | |||
@PathParam("id") String id, | |||
FlexRouter request) { | |||
// caller must be admin | |||
if (isReadOnly(ctx)) return forbidden(); | |||
// caller must come from a valid device | |||
final String remoteAddr = getRemoteAddr(req); | |||
final Device device = deviceService.findDeviceByIp(remoteAddr); | |||
if (device == null) return invalid("err.device.notFound"); | |||
final FlexRouter flexRouter = getDao().findByUuid(id); | |||
if (flexRouter == null) return notFound(id); | |||
// set token and return | |||
final String token = randomAlphanumeric(50); | |||
final FlexRouter updated = getDao().update(flexRouter | |||
.setPort(request.getPort()) | |||
.setLastSeen() | |||
.setToken(token)); | |||
return ok(updated.setServerToken(token)); | |||
} | |||
} |
@@ -24,7 +24,7 @@ import bubble.server.BubbleConfiguration; | |||
import bubble.service.block.BlockStatsService; | |||
import bubble.service.block.BlockStatsSummary; | |||
import bubble.service.boot.SelfNodeService; | |||
import bubble.service.cloud.DeviceIdService; | |||
import bubble.service.device.DeviceService; | |||
import bubble.service.stream.ConnectionCheckResponse; | |||
import bubble.service.stream.StandardRuleEngineService; | |||
import com.fasterxml.jackson.databind.JsonNode; | |||
@@ -79,7 +79,7 @@ public class FilterHttpResource { | |||
@Autowired private AppSiteDAO siteDAO; | |||
@Autowired private AppRuleDAO ruleDAO; | |||
@Autowired private DeviceDAO deviceDAO; | |||
@Autowired private DeviceIdService deviceIdService; | |||
@Autowired private DeviceService deviceService; | |||
@Autowired private RedisService redis; | |||
@Autowired private BubbleConfiguration configuration; | |||
@Autowired private SelfNodeService selfNodeService; | |||
@@ -163,7 +163,7 @@ public class FilterHttpResource { | |||
} | |||
final String vpnAddr = connCheckRequest.getRemoteAddr(); | |||
final Device device = deviceIdService.findDeviceByIp(vpnAddr); | |||
final Device device = deviceService.findDeviceByIp(vpnAddr); | |||
if (device == null) { | |||
if (log.isDebugEnabled()) log.debug(prefix+"device not found for IP "+vpnAddr+", returning not found"); | |||
return notFound(); | |||
@@ -237,17 +237,17 @@ public class FilterHttpResource { | |||
@Getter(lazy=true) private final BubbleNetwork thisNetwork = selfNodeService.getThisNetwork(); | |||
public boolean showStats(String accountUuid, String ip, String[] fqdns) { | |||
if (!deviceIdService.doShowBlockStats(accountUuid)) return false; | |||
if (!deviceService.doShowBlockStats(accountUuid)) return false; | |||
for (String fqdn : fqdns) { | |||
final Boolean show = deviceIdService.doShowBlockStatsForIpAndFqdn(ip, fqdn); | |||
final Boolean show = deviceService.doShowBlockStatsForIpAndFqdn(ip, fqdn); | |||
if (show != null) return show; | |||
} | |||
return true; | |||
} | |||
public boolean showStats(String accountUuid, String ip, String fqdn) { | |||
if (!deviceIdService.doShowBlockStats(accountUuid)) return false; | |||
final Boolean show = deviceIdService.doShowBlockStatsForIpAndFqdn(ip, fqdn); | |||
if (!deviceService.doShowBlockStats(accountUuid)) return false; | |||
final Boolean show = deviceService.doShowBlockStatsForIpAndFqdn(ip, fqdn); | |||
return show == null || show; | |||
} | |||
@@ -277,7 +277,7 @@ public class FilterHttpResource { | |||
} | |||
final String vpnAddr = filterRequest.getClientAddr(); | |||
final Device device = deviceIdService.findDeviceByIp(vpnAddr); | |||
final Device device = deviceService.findDeviceByIp(vpnAddr); | |||
if (device == null) { | |||
if (log.isDebugEnabled()) log.debug(prefix+"device not found for IP "+vpnAddr+", returning no matchers"); | |||
else if (extraLog) log.error(prefix+"device not found for IP "+vpnAddr+", returning no matchers"); | |||
@@ -11,7 +11,7 @@ import bubble.model.app.AppMatcher; | |||
import bubble.model.device.Device; | |||
import bubble.rule.FilterMatchDecision; | |||
import bubble.server.BubbleConfiguration; | |||
import bubble.service.cloud.DeviceIdService; | |||
import bubble.service.device.DeviceService; | |||
import bubble.service.stream.StandardRuleEngineService; | |||
import lombok.Getter; | |||
import lombok.extern.slf4j.Slf4j; | |||
@@ -46,7 +46,7 @@ public class ReverseProxyResource { | |||
@Autowired private AppMatcherDAO matcherDAO; | |||
@Autowired private AppRuleDAO ruleDAO; | |||
@Autowired private StandardRuleEngineService ruleEngine; | |||
@Autowired private DeviceIdService deviceIdService; | |||
@Autowired private DeviceService deviceService; | |||
@Autowired private FilterHttpResource filterHttpResource; | |||
@Getter(lazy=true) private final int prefixLength = configuration.getHttp().getBaseUri().length() + PROXY_ENDPOINT.length() + 1; | |||
@@ -60,7 +60,7 @@ public class ReverseProxyResource { | |||
@PathParam("path") String path) throws URISyntaxException, IOException { | |||
final Account account = userPrincipal(request); | |||
final String remoteHost = getRemoteHost(req); | |||
final Device device = deviceIdService.findDeviceByIp(remoteHost); | |||
final Device device = deviceService.findDeviceByIp(remoteHost); | |||
if (device == null) return ruleEngine.passthru(request); | |||
final URIBean ub = getUriBean(request); | |||
@@ -16,7 +16,7 @@ import bubble.model.device.Device; | |||
import bubble.resources.stream.FilterHttpRequest; | |||
import bubble.resources.stream.FilterMatchersRequest; | |||
import bubble.server.BubbleConfiguration; | |||
import bubble.service.cloud.StandardDeviceIdService; | |||
import bubble.service.device.StandardDeviceService; | |||
import bubble.service.stream.AppPrimerService; | |||
import com.fasterxml.jackson.databind.JsonNode; | |||
import com.github.jknack.handlebars.Handlebars; | |||
@@ -64,7 +64,7 @@ public abstract class AbstractAppRuleDriver implements AppRuleDriver { | |||
@Autowired protected BubbleNetworkDAO networkDAO; | |||
@Autowired protected DeviceDAO deviceDAO; | |||
@Autowired protected AppPrimerService appPrimerService; | |||
@Autowired protected StandardDeviceIdService deviceService; | |||
@Autowired protected StandardDeviceService deviceService; | |||
@Getter @Setter private AppRuleDriver next; | |||
@@ -16,7 +16,7 @@ import bubble.rule.RequestModifierConfig; | |||
import bubble.rule.RequestModifierRule; | |||
import bubble.rule.analytics.TrafficAnalyticsRuleDriver; | |||
import bubble.server.BubbleConfiguration; | |||
import bubble.service.cloud.DeviceIdService; | |||
import bubble.service.device.DeviceService; | |||
import bubble.service.stream.AppRuleHarness; | |||
import bubble.service.stream.ConnectionCheckResponse; | |||
import com.fasterxml.jackson.databind.JsonNode; | |||
@@ -419,11 +419,11 @@ public class BubbleBlockRuleDriver extends TrafficAnalyticsRuleDriver | |||
} | |||
@Override public void prime(Account account, BubbleApp app, BubbleConfiguration configuration) { | |||
final DeviceIdService deviceIdService = configuration.getBean(DeviceIdService.class); | |||
final DeviceService deviceService = configuration.getBean(DeviceService.class); | |||
final AppDataDAO dataDAO = configuration.getBean(AppDataDAO.class); | |||
log.info("priming app="+app.getName()); | |||
dataDAO.findByAccountAndAppAndAndKeyPrefix(account.getUuid(), app.getUuid(), PREFIX_APPDATA_HIDE_STATS) | |||
.forEach(data -> deviceIdService.setBlockStatsForFqdn(account, fqdnFromKey(data.getKey()), !Boolean.parseBoolean(data.getData()))); | |||
.forEach(data -> deviceService.setBlockStatsForFqdn(account, fqdnFromKey(data.getKey()), !Boolean.parseBoolean(data.getData()))); | |||
} | |||
@Override public Function<AppData, AppData> createCallback(Account account, | |||
@@ -433,15 +433,15 @@ public class BubbleBlockRuleDriver extends TrafficAnalyticsRuleDriver | |||
final String prefix = "createCallbackB("+data.getKey()+"="+data.getData()+"): "; | |||
log.info(prefix+"starting"); | |||
if (data.getKey().startsWith(PREFIX_APPDATA_HIDE_STATS)) { | |||
final DeviceIdService deviceIdService = configuration.getBean(DeviceIdService.class); | |||
final DeviceService deviceService = configuration.getBean(DeviceService.class); | |||
final String fqdn = fqdnFromKey(data.getKey()); | |||
if (validateRegexMatches(HOST_PATTERN, fqdn)) { | |||
if (data.deleting()) { | |||
log.info(prefix+"unsetting fqdn: "+fqdn); | |||
deviceIdService.unsetBlockStatsForFqdn(account, fqdn); | |||
deviceService.unsetBlockStatsForFqdn(account, fqdn); | |||
} else { | |||
log.info(prefix+"setting fqdn: "+fqdn); | |||
deviceIdService.setBlockStatsForFqdn(account, fqdn, !Boolean.parseBoolean(data.getData())); | |||
deviceService.setBlockStatsForFqdn(account, fqdn, !Boolean.parseBoolean(data.getData())); | |||
} | |||
} else { | |||
throw invalidEx("err.fqdn.invalid", "not a valid FQDN: "+fqdn, fqdn); | |||
@@ -13,8 +13,9 @@ import bubble.model.cloud.BubbleNode; | |||
import bubble.model.cloud.CloudService; | |||
import bubble.server.BubbleConfiguration; | |||
import bubble.service.boot.SelfNodeService; | |||
import bubble.service.cloud.DeviceIdService; | |||
import bubble.service.device.DeviceService; | |||
import bubble.service.cloud.NetworkMonitorService; | |||
import bubble.service.device.FlexRouterService; | |||
import bubble.service.stream.AppDataCleaner; | |||
import bubble.service.stream.AppPrimerService; | |||
import lombok.extern.slf4j.Slf4j; | |||
@@ -112,7 +113,8 @@ public class NodeInitializerListener extends RestServerLifecycleListenerBase<Bub | |||
final BubbleNetwork thisNetwork = c.getThisNetwork(); | |||
if (thisNetwork != null && thisNetwork.getInstallType() == AnsibleInstallType.node) { | |||
c.getBean(AppPrimerService.class).primeApps(); | |||
c.getBean(DeviceIdService.class).initDeviceSecurityLevels(); | |||
c.getBean(FlexRouterService.class).start(); | |||
c.getBean(DeviceService.class).initDeviceSecurityLevels(); | |||
c.getBean(AppDataCleaner.class).start(); | |||
} | |||
} | |||
@@ -24,6 +24,7 @@ import bubble.model.cloud.BubbleNodeKey; | |||
import bubble.model.cloud.notify.ReceivedNotification; | |||
import bubble.model.cloud.notify.SentNotification; | |||
import bubble.model.device.Device; | |||
import bubble.model.device.FlexRouter; | |||
import bubble.server.BubbleConfiguration; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.cobbzilla.wizard.dao.DAO; | |||
@@ -39,14 +40,14 @@ import static org.cobbzilla.util.daemon.ZillaRuntime.die; | |||
@Slf4j | |||
public class FilteredEntityIterator extends EntityIterator { | |||
private static final List<Class<? extends Identifiable>> POST_COPY_ENTITIES = Arrays.asList(new Class[] { | |||
private static final List<Class<? extends Identifiable>> NO_DEFAULT_COPY_ENTITIES = Arrays.asList(new Class[] { | |||
BubbleNode.class, BubbleNodeKey.class, Device.class, AccountMessage.class, | |||
ReferralCode.class, AccountPayment.class, Bill.class, Promotion.class, | |||
ReceivedNotification.class, SentNotification.class, TrustedClient.class | |||
ReceivedNotification.class, SentNotification.class, TrustedClient.class, FlexRouter.class | |||
}); | |||
private static boolean isPostCopyEntity(Class<? extends Identifiable> clazz) { | |||
return POST_COPY_ENTITIES.stream().anyMatch(c -> c.isAssignableFrom(clazz)); | |||
private static boolean isNotDefaultCopyEntity(Class<? extends Identifiable> clazz) { | |||
return NO_DEFAULT_COPY_ENTITIES.stream().anyMatch(c -> c.isAssignableFrom(clazz)); | |||
} | |||
private final BubbleConfiguration configuration; | |||
@@ -82,10 +83,10 @@ public class FilteredEntityIterator extends EntityIterator { | |||
configuration.getEntityClasses().forEach(c -> { | |||
final DAO dao = configuration.getDaoForEntityClass(c); | |||
if (!AccountOwnedEntityDAO.class.isAssignableFrom(dao.getClass())) { | |||
log.debug("iterate: skipping entity: " + c.getSimpleName()); | |||
} else if (isPostCopyEntity(c)) { | |||
log.debug("iterate: skipping entity, not an AccountOwnedEntityDAO: " + c.getSimpleName()); | |||
} else if (isNotDefaultCopyEntity(c)) { | |||
log.debug("iterate: skipping " + c.getSimpleName() | |||
+ ", will copy some of these after other objects are copied"); | |||
+ ", may copy some of these after default objects are copied"); | |||
} else { | |||
// copy entities. this is how the re-keying works (decrypt using current spring config, | |||
// encrypt using new config) | |||
@@ -2,7 +2,7 @@ | |||
* Copyright (c) 2020 Bubble, Inc. All rights reserved. | |||
* For personal (non-commercial) use, see license: https://getbubblenow.com/bubble-license/ | |||
*/ | |||
package bubble.service.cloud; | |||
package bubble.service.device; | |||
import bubble.model.account.Account; | |||
import bubble.model.device.Device; | |||
@@ -10,7 +10,7 @@ import bubble.model.device.DeviceStatus; | |||
import java.util.List; | |||
public interface DeviceIdService { | |||
public interface DeviceService { | |||
Device findDeviceByIp(String ip); | |||
@@ -0,0 +1,58 @@ | |||
package bubble.service.device; | |||
import bubble.dao.device.FlexRouterDAO; | |||
import bubble.model.device.FlexRouter; | |||
import lombok.Getter; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.cobbzilla.util.daemon.SimpleDaemon; | |||
import org.cobbzilla.util.http.HttpRequestBean; | |||
import org.cobbzilla.util.http.HttpResponseBean; | |||
import org.cobbzilla.util.http.HttpUtil; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
import org.springframework.stereotype.Service; | |||
import java.util.List; | |||
import static java.util.concurrent.TimeUnit.MINUTES; | |||
import static org.cobbzilla.util.daemon.ZillaRuntime.shortError; | |||
import static org.cobbzilla.util.http.HttpMethods.POST; | |||
@Service @Slf4j | |||
public class FlexRouterService extends SimpleDaemon { | |||
@Getter private final long sleepTime = MINUTES.toMillis(2); | |||
@Autowired private FlexRouterDAO flexRouterDAO; | |||
@Override protected void process() { | |||
try { | |||
final List<FlexRouter> routers = flexRouterDAO.findEnabledAndRegistered(); | |||
for (FlexRouter router : routers) { | |||
FlexRouter update = pingRouter(router); | |||
if (update != null) { | |||
flexRouterDAO.update(update); | |||
} | |||
} | |||
} catch (Exception e) { | |||
log.error("process: "+shortError(e)); | |||
} | |||
} | |||
private FlexRouter pingRouter(FlexRouter router) { | |||
final String prefix = "pingRouter(" + router + "): "; | |||
final HttpRequestBean request = new HttpRequestBean(POST, router.pingUrl(), router.pingObject()); | |||
try { | |||
final HttpResponseBean response = HttpUtil.getResponse(request); | |||
if (!response.isOk()) { | |||
log.error(prefix+"response not OK, marking inactive: "+response); | |||
return router.setActive(false); | |||
} | |||
return router.setActive(true).setLastSeen(); | |||
} catch (Exception e) { | |||
log.error(prefix+"error (marking inactive): "+shortError(e)); | |||
return router.setActive(false); | |||
} | |||
} | |||
} |
@@ -2,7 +2,7 @@ | |||
* Copyright (c) 2020 Bubble, Inc. All rights reserved. | |||
* For personal (non-commercial) use, see license: https://getbubblenow.com/bubble-license/ | |||
*/ | |||
package bubble.service.cloud; | |||
package bubble.service.device; | |||
import bubble.dao.account.AccountDAO; | |||
import bubble.dao.app.AppSiteDAO; | |||
@@ -12,6 +12,7 @@ import bubble.model.app.AppSite; | |||
import bubble.model.device.Device; | |||
import bubble.model.device.DeviceStatus; | |||
import bubble.server.BubbleConfiguration; | |||
import bubble.service.cloud.GeoService; | |||
import bubble.service.stream.StandardRuleEngineService; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.cobbzilla.util.collection.ExpirationMap; | |||
@@ -40,7 +41,7 @@ import static org.cobbzilla.wizard.resources.ResourceUtil.invalidEx; | |||
import static org.cobbzilla.wizard.server.RestServerBase.reportError; | |||
@Service @Slf4j | |||
public class StandardDeviceIdService implements DeviceIdService { | |||
public class StandardDeviceService implements DeviceService { | |||
public static final File WG_DEVICES_DIR = new File(HOME_DIR, "wg_devices"); | |||
@@ -14,7 +14,7 @@ import bubble.model.cloud.BubbleNetwork; | |||
import bubble.model.device.Device; | |||
import bubble.rule.AppRuleDriver; | |||
import bubble.server.BubbleConfiguration; | |||
import bubble.service.cloud.DeviceIdService; | |||
import bubble.service.device.DeviceService; | |||
import lombok.Getter; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.cobbzilla.util.collection.SingletonList; | |||
@@ -34,7 +34,7 @@ public class StandardAppPrimerService implements AppPrimerService { | |||
@Autowired private AccountDAO accountDAO; | |||
@Autowired private DeviceDAO deviceDAO; | |||
@Autowired private DeviceIdService deviceIdService; | |||
@Autowired private DeviceService deviceService; | |||
@Autowired private BubbleAppDAO appDAO; | |||
@Autowired private AppMatcherDAO matcherDAO; | |||
@Autowired private AppRuleDAO ruleDAO; | |||
@@ -77,7 +77,7 @@ public class StandardAppPrimerService implements AppPrimerService { | |||
} | |||
public void prime(Account account) { | |||
deviceIdService.initBlockStats(account); | |||
deviceService.initBlockStats(account); | |||
prime(account, (BubbleApp) null); | |||
} | |||
@@ -114,7 +114,7 @@ public class StandardAppPrimerService implements AppPrimerService { | |||
final Map<String, List<String>> accountDeviceIps = new HashMap<>(); | |||
final List<Device> devices = deviceDAO.findByAccount(account.getUuid()); | |||
for (Device device : devices) { | |||
accountDeviceIps.put(device.getUuid(), deviceIdService.findIpsByDevice(device.getUuid())); | |||
accountDeviceIps.put(device.getUuid(), deviceService.findIpsByDevice(device.getUuid())); | |||
} | |||
if (accountDeviceIps.isEmpty()) return; | |||
@@ -7,7 +7,7 @@ package bubble.service_dbfilter; | |||
import bubble.model.account.Account; | |||
import bubble.model.device.Device; | |||
import bubble.model.device.DeviceStatus; | |||
import bubble.service.cloud.DeviceIdService; | |||
import bubble.service.device.DeviceService; | |||
import org.springframework.stereotype.Service; | |||
import java.util.List; | |||
@@ -15,7 +15,7 @@ import java.util.List; | |||
import static org.cobbzilla.util.daemon.ZillaRuntime.notSupported; | |||
@Service | |||
public class DbFilterDeviceIdService implements DeviceIdService { | |||
public class DbFilterDeviceService implements DeviceService { | |||
@Override public Device findDeviceByIp(String ip) { return notSupported("findDeviceByIp"); } | |||
@@ -1 +1 @@ | |||
Subproject commit 9fcd7bc0a768b124b09b7e8995c27fc94dedf9d8 | |||
Subproject commit 2b4074ab37b1e3caa0cb6382352b3391f5bb7139 |
@@ -1 +1 @@ | |||
Subproject commit 4dcca7b4ca0240ad7f2cc1d60909c0ff5830339a | |||
Subproject commit 7727825b5e738168a42e4148d873c3f75d572f91 |