@@ -131,6 +131,8 @@ public class FilterHttpResource { | |||
final List<AppMatcher> matchers = matcherDAO.findByAccountAndFqdnAndEnabled(accountUuid, fqdn); | |||
if (log.isDebugEnabled()) log.debug("findMatchers: found "+matchers.size()+" candidate matchers"); | |||
final List<AppMatcher> removeMatchers; | |||
List<String> options = null; | |||
List<String> selectors = null; | |||
if (matchers.isEmpty()) { | |||
removeMatchers = Collections.emptyList(); | |||
} else { | |||
@@ -138,12 +140,23 @@ public class FilterHttpResource { | |||
removeMatchers = new ArrayList<>(); | |||
for (AppMatcher matcher : matchers) { | |||
if (matcher.matches(uri)) { | |||
switch (ruleEngine.preprocess(filterRequest, req, request, caller, device, matcher.getUuid())) { | |||
final FilterMatchResponse matchResponse = ruleEngine.preprocess(filterRequest, req, request, caller, device, matcher.getUuid()); | |||
switch (matchResponse.getDecision()) { | |||
case abort_ok: return ABORT_OK; | |||
case abort_not_found: return ABORT_NOT_FOUND; | |||
case no_match: | |||
removeMatchers.add(matcher); | |||
break; | |||
case abort_ok: return ABORT_OK; | |||
case abort_not_found: return ABORT_NOT_FOUND; | |||
case match: | |||
if (matchResponse.hasOptions()) { | |||
if (options == null) options = new ArrayList<>(); | |||
options.addAll(matchResponse.getOptions()); | |||
} | |||
if (matchResponse.hasSelectors()) { | |||
if (selectors == null) selectors = new ArrayList<>(); | |||
selectors.addAll(matchResponse.getSelectors()); | |||
} | |||
break; | |||
} | |||
} | |||
} | |||
@@ -151,7 +164,12 @@ public class FilterHttpResource { | |||
matchers.removeAll(removeMatchers); | |||
if (log.isDebugEnabled()) log.debug("findMatchers: after pre-processing, returning "+matchers.size()+" matchers"); | |||
return new FilterMatchersResponse().setMatchers(matchers).setDevice(device.getUuid()); | |||
final FilterMatchersResponse response = new FilterMatchersResponse(); | |||
return response | |||
.setMatchers(matchers) | |||
.setDevice(device.getUuid()) | |||
.setOptions(options) | |||
.setSelectors(selectors); | |||
} | |||
@POST @Path(EP_APPLY+"/{requestId}") | |||
@@ -0,0 +1,27 @@ | |||
package bubble.resources.stream; | |||
import bubble.rule.FilterMatchDecision; | |||
import lombok.Getter; | |||
import lombok.NoArgsConstructor; | |||
import lombok.Setter; | |||
import lombok.experimental.Accessors; | |||
import java.util.List; | |||
@NoArgsConstructor @Accessors(chain=true) | |||
public class FilterMatchResponse { | |||
public static final FilterMatchResponse NO_MATCH = new FilterMatchResponse().setDecision(FilterMatchDecision.no_match); | |||
public static final FilterMatchResponse MATCH = new FilterMatchResponse().setDecision(FilterMatchDecision.match); | |||
public static final FilterMatchResponse ABORT_NOT_FOUND = new FilterMatchResponse().setDecision(FilterMatchDecision.abort_not_found); | |||
public static final FilterMatchResponse ABORT_OK = new FilterMatchResponse().setDecision(FilterMatchDecision.abort_ok); | |||
@Getter @Setter private FilterMatchDecision decision; | |||
@Getter @Setter private List<String> options; | |||
public boolean hasOptions () { return options != null && !options.isEmpty(); } | |||
@Getter @Setter private List<String> selectors; | |||
public boolean hasSelectors () { return selectors != null && !selectors.isEmpty(); } | |||
} |
@@ -16,5 +16,7 @@ public class FilterMatchersResponse { | |||
@Getter @Setter private Integer abort; | |||
@Getter @Setter private String device; | |||
@Getter @Setter private List<AppMatcher> matchers; | |||
@Getter @Setter private List<String> options; | |||
@Getter @Setter private List<String> selectors; | |||
} |
@@ -4,6 +4,7 @@ import bubble.model.account.Account; | |||
import bubble.model.app.AppMatcher; | |||
import bubble.model.app.AppRule; | |||
import bubble.model.device.Device; | |||
import bubble.resources.stream.FilterMatchResponse; | |||
import bubble.service.stream.AppRuleHarness; | |||
import bubble.resources.stream.FilterMatchersRequest; | |||
import com.fasterxml.jackson.databind.JsonNode; | |||
@@ -32,13 +33,13 @@ public interface AppRuleDriver { | |||
Account account, | |||
Device device) {} | |||
default PreprocessDecision preprocess(AppRuleHarness ruleHarness, | |||
FilterMatchersRequest filter, | |||
Account account, | |||
Device device, | |||
Request req, | |||
ContainerRequest request) { | |||
return PreprocessDecision.match; | |||
default FilterMatchResponse preprocess(AppRuleHarness ruleHarness, | |||
FilterMatchersRequest filter, | |||
Account account, | |||
Device device, | |||
Request req, | |||
ContainerRequest request) { | |||
return FilterMatchResponse.MATCH; | |||
} | |||
default InputStream filterRequest(InputStream in) { | |||
@@ -4,13 +4,13 @@ import com.fasterxml.jackson.annotation.JsonCreator; | |||
import static bubble.ApiConstants.enumFromString; | |||
public enum PreprocessDecision { | |||
public enum FilterMatchDecision { | |||
no_match, // associated matcher should not be included in request processing | |||
match, // associated should be included in request processing | |||
abort_ok, // abort request processing, return empty 200 OK response to client | |||
abort_not_found; // abort request processing, return empty 404 Not Found response to client | |||
@JsonCreator public static PreprocessDecision fromString (String v) { return enumFromString(PreprocessDecision.class, v); } | |||
@JsonCreator public static FilterMatchDecision fromString (String v) { return enumFromString(FilterMatchDecision.class, v); } | |||
} |
@@ -3,9 +3,9 @@ package bubble.rule.analytics; | |||
import bubble.model.account.Account; | |||
import bubble.model.app.AppData; | |||
import bubble.model.device.Device; | |||
import bubble.resources.stream.FilterMatchResponse; | |||
import bubble.resources.stream.FilterMatchersRequest; | |||
import bubble.rule.AbstractAppRuleDriver; | |||
import bubble.rule.PreprocessDecision; | |||
import bubble.service.stream.AppRuleHarness; | |||
import lombok.Getter; | |||
import org.cobbzilla.wizard.cache.redis.RedisService; | |||
@@ -30,12 +30,12 @@ public class TrafficAnalytics extends AbstractAppRuleDriver { | |||
@Getter(lazy=true) private final RedisService recentTraffic = redis.prefixNamespace(RECENT_TRAFFIC_PREFIX); | |||
@Override public PreprocessDecision preprocess(AppRuleHarness ruleHarness, | |||
FilterMatchersRequest filter, | |||
Account account, | |||
Device device, | |||
Request req, | |||
ContainerRequest request) { | |||
@Override public FilterMatchResponse preprocess(AppRuleHarness ruleHarness, | |||
FilterMatchersRequest filter, | |||
Account account, | |||
Device device, | |||
Request req, | |||
ContainerRequest request) { | |||
final String app = ruleHarness.getRule().getApp(); | |||
final String site = ruleHarness.getMatcher().getSite(); | |||
final String fqdn = filter.getFqdn(); | |||
@@ -43,7 +43,7 @@ public class TrafficAnalytics extends AbstractAppRuleDriver { | |||
getRecentTraffic().set(now()+"_"+randomAlphanumeric(10), json(new TrafficRecord(filter, account, device, req)), EX, RECENT_TRAFFIC_EXPIRATION); | |||
incr(account, device, app, site, fqdn, DATE_FORMAT_YYYY_MM_DD_HH.print(now())); | |||
incr(account, null, app, site, fqdn, DATE_FORMAT_YYYY_MM_DD_HH.print(now())); | |||
return PreprocessDecision.no_match; // we are done, don't need to look at/modify stream | |||
return FilterMatchResponse.NO_MATCH; // we are done, don't need to look at/modify stream | |||
} | |||
// we use synchronized here but in a multi-node scenario this is not sufficient, we still have some risk | |||
@@ -1,39 +1,87 @@ | |||
package bubble.rule.bblock; | |||
import bubble.model.account.Account; | |||
import bubble.model.app.AppMatcher; | |||
import bubble.model.app.AppRule; | |||
import bubble.model.device.Device; | |||
import bubble.resources.stream.FilterMatchResponse; | |||
import bubble.resources.stream.FilterMatchersRequest; | |||
import bubble.rule.PreprocessDecision; | |||
import bubble.rule.analytics.TrafficAnalytics; | |||
import bubble.rule.bblock.spec.BlockDecision; | |||
import bubble.rule.bblock.spec.BlockList; | |||
import bubble.rule.bblock.spec.BlockListSource; | |||
import bubble.service.stream.AppRuleHarness; | |||
import com.fasterxml.jackson.databind.JsonNode; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.glassfish.grizzly.http.server.Request; | |||
import org.glassfish.jersey.server.ContainerRequest; | |||
import java.io.InputStream; | |||
import java.util.Map; | |||
import java.util.concurrent.ConcurrentHashMap; | |||
import java.util.concurrent.TimeUnit; | |||
import static org.cobbzilla.util.daemon.ZillaRuntime.now; | |||
import static org.cobbzilla.util.daemon.ZillaRuntime.shortError; | |||
import static org.cobbzilla.util.json.JsonUtil.json; | |||
import static org.cobbzilla.util.time.TimeUtil.DATE_FORMAT_YYYY_MM_DD_HH; | |||
@Slf4j | |||
public class BubbleBlock extends TrafficAnalytics { | |||
@Override public PreprocessDecision preprocess(AppRuleHarness ruleHarness, | |||
FilterMatchersRequest filter, | |||
Account account, | |||
Device device, | |||
Request req, | |||
ContainerRequest request) { | |||
private BubbleBlockConfig bubbleBlockConfig; | |||
private BlockList blockList = new BlockList(); | |||
private static Map<String, BlockListSource> blockListCache = new ConcurrentHashMap<>(); | |||
@Override public void init(JsonNode config, JsonNode userConfig, AppRule rule, AppMatcher matcher, Account account, Device device) { | |||
super.init(config, userConfig, rule, matcher, account, device); | |||
bubbleBlockConfig = json(json(config), BubbleBlockConfig.class); | |||
for (String listUrl : bubbleBlockConfig.getBlockLists()) { | |||
BlockListSource blockListSource = blockListCache.get(listUrl); | |||
if (blockListSource == null || blockListSource.age() > TimeUnit.DAYS.toMillis(5)) { | |||
try { | |||
final BlockListSource newList = new BlockListSource() | |||
.setUrl(listUrl) | |||
.download(); | |||
blockListCache.put(listUrl, newList); | |||
blockListSource = newList; | |||
} catch (Exception e) { | |||
log.error("init: error downloading blocklist "+listUrl+": "+shortError(e)); | |||
continue; | |||
} | |||
} | |||
blockList.merge(blockListSource.getBlockList()); | |||
} | |||
} | |||
@Override public FilterMatchResponse preprocess(AppRuleHarness ruleHarness, | |||
FilterMatchersRequest filter, | |||
Account account, | |||
Device device, | |||
Request req, | |||
ContainerRequest request) { | |||
final String app = ruleHarness.getRule().getApp(); | |||
final String site = ruleHarness.getMatcher().getSite(); | |||
final String fqdn = filter.getFqdn(); | |||
if (shouldBlock(account, device, filter)) { | |||
incr(account, device, app, site, fqdn, DATE_FORMAT_YYYY_MM_DD_HH.print(now())); | |||
incr(account, null, app, site, fqdn, DATE_FORMAT_YYYY_MM_DD_HH.print(now())); | |||
return PreprocessDecision.abort_not_found; // block this request | |||
final BlockDecision decision = blockList.getDecision(filter.getFqdn(), filter.getUri()); | |||
switch (decision.getDecisionType()) { | |||
case block: | |||
incr(account, device, app, site, fqdn, DATE_FORMAT_YYYY_MM_DD_HH.print(now())); | |||
incr(account, null, app, site, fqdn, DATE_FORMAT_YYYY_MM_DD_HH.print(now())); | |||
return FilterMatchResponse.ABORT_NOT_FOUND; // block this request | |||
case allow: default: | |||
return FilterMatchResponse.NO_MATCH; | |||
case filter: | |||
return decision.getFilterMatchResponse(); | |||
} | |||
return PreprocessDecision.no_match; // don't block, and don't process this matcher (we do not modify streams) | |||
} | |||
private boolean shouldBlock(Account account, Device device, FilterMatchersRequest filter) { | |||
return false; | |||
@Override public InputStream doFilterResponse(String requestId, InputStream in) { | |||
// todo : insert selector-based block JS | |||
return in; | |||
} | |||
} |
@@ -0,0 +1,12 @@ | |||
package bubble.rule.bblock; | |||
import lombok.Getter; | |||
import lombok.NoArgsConstructor; | |||
import lombok.Setter; | |||
@NoArgsConstructor | |||
public class BubbleBlockConfig { | |||
@Getter @Setter private String[] blockLists; | |||
} |
@@ -0,0 +1,59 @@ | |||
package bubble.rule.bblock.spec; | |||
import bubble.resources.stream.FilterMatchResponse; | |||
import bubble.rule.FilterMatchDecision; | |||
import lombok.Getter; | |||
import lombok.NoArgsConstructor; | |||
import lombok.Setter; | |||
import lombok.experimental.Accessors; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import static org.cobbzilla.util.daemon.ZillaRuntime.die; | |||
import static org.cobbzilla.util.daemon.ZillaRuntime.empty; | |||
@NoArgsConstructor @Accessors(chain=true) | |||
public class BlockDecision { | |||
public static final BlockDecision BLOCK = new BlockDecision().setDecisionType(BlockDecisionType.block); | |||
public static final BlockDecision ALLOW = new BlockDecision().setDecisionType(BlockDecisionType.allow); | |||
@Getter @Setter BlockDecisionType decisionType = BlockDecisionType.allow; | |||
@Getter @Setter List<String> selectors; | |||
@Getter @Setter List<String> options; | |||
public BlockDecision add(BlockSpec block) { | |||
if (block.hasSelector()) { | |||
if (selectors == null) selectors = new ArrayList<>(); | |||
selectors.add(block.getSelector()); | |||
} | |||
if (block.hasOptions()) { | |||
if (options == null) options = new ArrayList<>(); | |||
options.addAll(block.getOptions()); | |||
} | |||
if (!empty(selectors) || !empty(options)) decisionType = BlockDecisionType.filter; | |||
return this; | |||
} | |||
public FilterMatchDecision getFilterMatchDecision() { | |||
switch (decisionType) { | |||
case block: return FilterMatchDecision.abort_not_found; | |||
case allow: return FilterMatchDecision.no_match; | |||
case filter: return FilterMatchDecision.match; | |||
} | |||
return die("getFilterMatchDecision: invalid decisionType: "+decisionType); | |||
} | |||
public FilterMatchResponse getFilterMatchResponse() { | |||
switch (decisionType) { | |||
case block: return FilterMatchResponse.ABORT_NOT_FOUND; | |||
case allow: return FilterMatchResponse.NO_MATCH; | |||
case filter: return new FilterMatchResponse() | |||
.setDecision(FilterMatchDecision.match) | |||
.setOptions(getOptions()) | |||
.setSelectors(getSelectors()); | |||
} | |||
return die("getFilterMatchResponse: invalid decisionType: "+decisionType); | |||
} | |||
} |
@@ -0,0 +1,13 @@ | |||
package bubble.rule.bblock.spec; | |||
import com.fasterxml.jackson.annotation.JsonCreator; | |||
import static bubble.ApiConstants.enumFromString; | |||
public enum BlockDecisionType { | |||
block, allow, filter; | |||
@JsonCreator public static BlockDecisionType fromString (String v) { return enumFromString(BlockDecisionType.class, v); } | |||
} |
@@ -0,0 +1,55 @@ | |||
package bubble.rule.bblock.spec; | |||
import lombok.Getter; | |||
import lombok.NoArgsConstructor; | |||
import lombok.experimental.Accessors; | |||
import lombok.extern.slf4j.Slf4j; | |||
import java.util.*; | |||
@NoArgsConstructor @Accessors(chain=true) @Slf4j | |||
public class BlockList { | |||
@Getter private Set<BlockSpec> blacklist = new HashSet<>(); | |||
@Getter private Set<BlockSpec> whitelist = new HashSet<>(); | |||
public void addToWhitelist(BlockSpec spec) { | |||
whitelist.add(spec); | |||
} | |||
public void addToWhitelist(List<BlockSpec> specs) { | |||
for (BlockSpec spec : specs) addToWhitelist(spec); | |||
} | |||
public void addToBlacklist(BlockSpec spec) { | |||
blacklist.add(spec); | |||
} | |||
public void addToBlacklist(List<BlockSpec> specs) { | |||
for (BlockSpec spec : specs) addToBlacklist(spec); | |||
} | |||
public void merge(BlockList other) { | |||
for (BlockSpec allow : other.getWhitelist()) { | |||
addToWhitelist(allow); | |||
} | |||
for (BlockSpec block : other.getBlacklist()) { | |||
addToBlacklist(block); | |||
} | |||
} | |||
public BlockDecision getDecision(String fqdn, String path) { | |||
for (BlockSpec allow : whitelist) { | |||
if (allow.matches(fqdn, path)) return BlockDecision.ALLOW; | |||
} | |||
final BlockDecision decision = new BlockDecision(); | |||
for (BlockSpec block : blacklist) { | |||
if (block.matches(fqdn, path)) { | |||
if (!block.hasSelector()) return BlockDecision.BLOCK; | |||
decision.add(block); | |||
} | |||
} | |||
return decision; | |||
} | |||
} |
@@ -0,0 +1,55 @@ | |||
package bubble.rule.bblock.spec; | |||
import lombok.Getter; | |||
import lombok.NoArgsConstructor; | |||
import lombok.Setter; | |||
import lombok.experimental.Accessors; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.cobbzilla.util.http.HttpUtil; | |||
import java.io.BufferedReader; | |||
import java.io.IOException; | |||
import java.io.InputStreamReader; | |||
import static org.cobbzilla.util.daemon.ZillaRuntime.*; | |||
import static org.cobbzilla.util.daemon.ZillaRuntime.now; | |||
@NoArgsConstructor @Accessors(chain=true) @Slf4j | |||
public class BlockListSource { | |||
@Getter @Setter private String url; | |||
@Getter @Setter private String format; | |||
@Getter @Setter private Long lastDownloaded; | |||
public long age () { return lastDownloaded == null ? Long.MAX_VALUE : now() - lastDownloaded; } | |||
@Getter @Setter private BlockList blockList = new BlockList(); | |||
public BlockListSource download() throws IOException { | |||
try (BufferedReader r = new BufferedReader(new InputStreamReader(HttpUtil.get(url)))) { | |||
String line; | |||
boolean firstLine = true; | |||
while ( (line = r.readLine()) != null ) { | |||
if (empty(line)) continue; | |||
line = line.trim(); | |||
if (firstLine && line.startsWith("[") && line.endsWith("]")) { | |||
format = line.substring(1, line.length()-1); | |||
} | |||
firstLine = false; | |||
if (line.startsWith("!")) continue; | |||
try { | |||
if (line.startsWith("@@")) { | |||
blockList.addToWhitelist(BlockSpec.parse(line)); | |||
} else { | |||
blockList.addToBlacklist(BlockSpec.parse(line)); | |||
} | |||
} catch (Exception e) { | |||
log.warn("download("+url+"): error parsing line (skipping due to "+shortError(e)+"): " + line); | |||
} | |||
} | |||
} | |||
lastDownloaded = now(); | |||
return this; | |||
} | |||
} |
@@ -0,0 +1,76 @@ | |||
package bubble.rule.bblock.spec; | |||
import lombok.AllArgsConstructor; | |||
import lombok.Getter; | |||
import org.cobbzilla.util.string.StringUtil; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import java.util.regex.Pattern; | |||
import static org.cobbzilla.util.daemon.ZillaRuntime.empty; | |||
@AllArgsConstructor | |||
public class BlockSpec { | |||
@Getter private BlockSpecTarget target; | |||
@Getter private List<String> options; | |||
@Getter(lazy=true) private final Pattern domainPattern = Pattern.compile(target.getDomainRegex()); | |||
public boolean hasOptions () { return options != null && !options.isEmpty(); } | |||
@Getter private String selector; | |||
public boolean hasSelector() { return !empty(selector); } | |||
public boolean isBlanket() { return !hasOptions() && !hasSelector(); } | |||
public static List<BlockSpec> parse(String line) { | |||
line = line.trim(); | |||
int optionStartPos = line.indexOf('$'); | |||
int selectorStartPos = line.indexOf("##"); | |||
// sanity check that selectorStartPos > optionStartPos -- $ may occur AFTER ## if the selector contains a regex | |||
if (selectorStartPos != -1 && optionStartPos > selectorStartPos) optionStartPos = -1; | |||
final List<BlockSpecTarget> targets; | |||
final List<String> options; | |||
final String selector; | |||
if (optionStartPos == -1) { | |||
if (selectorStartPos == -1) { | |||
// no options, no selector, entire line is the target | |||
targets = BlockSpecTarget.parse(line); | |||
options = null; | |||
selector = null; | |||
} else { | |||
// no options, but selector present. split into target + selector | |||
targets = BlockSpecTarget.parse(line.substring(0, selectorStartPos)); | |||
options = null; | |||
selector = line.substring(selectorStartPos+1); | |||
} | |||
} else { | |||
if (selectorStartPos == -1) { | |||
// no selector, split into target + options | |||
targets = BlockSpecTarget.parse(line.substring(0, optionStartPos)); | |||
options = StringUtil.splitAndTrim(line.substring(optionStartPos+1), ","); | |||
selector = null; | |||
} else { | |||
// all 3 elements present | |||
targets = BlockSpecTarget.parse(line.substring(0, optionStartPos)); | |||
options = StringUtil.splitAndTrim(line.substring(optionStartPos + 1, selectorStartPos), ","); | |||
selector = line.substring(selectorStartPos+1); | |||
} | |||
} | |||
final List<BlockSpec> specs = new ArrayList<>(); | |||
for (BlockSpecTarget target : targets) specs.add(new BlockSpec(target, options, selector)); | |||
return specs; | |||
} | |||
public boolean matches(String fqdn, String path) { | |||
if (getDomainPattern().matcher(fqdn).find()) { | |||
return true; | |||
} | |||
return false; | |||
} | |||
} |
@@ -0,0 +1,40 @@ | |||
package bubble.rule.bblock.spec; | |||
import lombok.Getter; | |||
import lombok.NoArgsConstructor; | |||
import lombok.Setter; | |||
import lombok.experimental.Accessors; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import java.util.regex.Pattern; | |||
@NoArgsConstructor @Accessors(chain=true) | |||
public class BlockSpecTarget { | |||
@Getter @Setter private String domainRegex; | |||
@Getter @Setter private String regex; | |||
public static List<BlockSpecTarget> parse(String data) { | |||
final List<BlockSpecTarget> targets = new ArrayList<>(); | |||
for (String part : data.split(",")) { | |||
targets.add(parseTarget(part)); | |||
} | |||
return targets; | |||
} | |||
private static BlockSpecTarget parseTarget(String data) { | |||
String domainRegex = null; | |||
String regex = null; | |||
if (data.startsWith("||")) { | |||
final int caretPos = data.indexOf("^"); | |||
if (caretPos != -1) { | |||
domainRegex = ".*?"+Pattern.quote(data.substring(2, caretPos))+"$"; | |||
} else { | |||
} | |||
} | |||
return new BlockSpecTarget().setDomainRegex(domainRegex).setRegex(regex); | |||
} | |||
} |
@@ -9,9 +9,9 @@ import bubble.model.app.AppRule; | |||
import bubble.model.app.RuleDriver; | |||
import bubble.model.device.Device; | |||
import bubble.resources.stream.FilterHttpRequest; | |||
import bubble.resources.stream.FilterMatchResponse; | |||
import bubble.resources.stream.FilterMatchersRequest; | |||
import bubble.rule.AppRuleDriver; | |||
import bubble.rule.PreprocessDecision; | |||
import bubble.server.BubbleConfiguration; | |||
import lombok.Cleanup; | |||
import lombok.Getter; | |||
@@ -71,12 +71,12 @@ public class RuleEngineService { | |||
@Autowired private RuleDriverDAO driverDAO; | |||
@Autowired private BubbleConfiguration configuration; | |||
public PreprocessDecision preprocess(FilterMatchersRequest filter, | |||
Request req, | |||
ContainerRequest request, | |||
Account account, | |||
Device device, | |||
String matcherUuid) { | |||
public FilterMatchResponse preprocess(FilterMatchersRequest filter, | |||
Request req, | |||
ContainerRequest request, | |||
Account account, | |||
Device device, | |||
String matcherUuid) { | |||
final AppRuleHarness ruleHarness = initRules(account, device, new String[]{ matcherUuid }).get(0); | |||
return ruleHarness.getDriver().preprocess(ruleHarness, filter, account, device, req, request); | |||
} | |||
@@ -38,7 +38,7 @@ | |||
"priority": -1000, | |||
"config": { | |||
"blockLists": [ | |||
"https://v.firebog.net/hosts/Easylist.txt" | |||
] | |||
} | |||
}], | |||
@@ -0,0 +1,14 @@ | |||
package bubble.rule.bblock.spec; | |||
import org.junit.Test; | |||
import static org.junit.Assert.assertEquals; | |||
public class BlockListTest { | |||
@Test public void testBlanketBlock () throws Exception { | |||
final BlockList blockList = new BlockList(); | |||
blockList.addToBlacklist(BlockSpec.parse("||fredfiber.no^")); | |||
assertEquals("expected block", BlockDecisionType.block, blockList.getDecision("fredfiber.no", "/somepath").getDecisionType()); | |||
} | |||
} |
@@ -1 +1 @@ | |||
Subproject commit 0200670256919c7b11ce19b340c5cfb843551379 | |||
Subproject commit 78b8da16659be214013288328f932509ed4c9224 |