diff --git a/bubble-server/src/main/java/bubble/rule/AbstractAppRuleDriver.java b/bubble-server/src/main/java/bubble/rule/AbstractAppRuleDriver.java index 01901961..929cdc81 100644 --- a/bubble-server/src/main/java/bubble/rule/AbstractAppRuleDriver.java +++ b/bubble-server/src/main/java/bubble/rule/AbstractAppRuleDriver.java @@ -36,22 +36,18 @@ import java.util.HashMap; import java.util.Map; import static bubble.ApiConstants.HOME_DIR; +import static bubble.rule.RequestModifierRule.ICON_JS_TEMPLATE; import static org.cobbzilla.util.daemon.ZillaRuntime.die; import static org.cobbzilla.util.daemon.ZillaRuntime.empty; import static org.cobbzilla.util.io.regex.RegexReplacementFilter.DEFAULT_PREFIX_REPLACEMENT_WITH_MATCH; import static org.cobbzilla.util.json.JsonUtil.json; +import static org.cobbzilla.util.security.ShaUtil.sha256_hex; import static org.cobbzilla.util.string.StringUtil.UTF8cs; public abstract class AbstractAppRuleDriver implements AppRuleDriver { public static final int RESPONSE_BUFSIZ = (int) (64 * Bytes.KB); - public static final String CTX_JS_PREFIX = "JS_PREFIX"; - public static final String CTX_BUBBLE_REQUEST_ID = "BUBBLE_REQUEST_ID"; - public static final String CTX_BUBBLE_DATA_ID = "BUBBLE_DATA_ID"; - public static final String CTX_BUBBLE_HOME = "BUBBLE_HOME"; - public static final String CTX_SITE = "SITE"; - @Autowired protected BubbleConfiguration configuration; @Autowired protected AppDataDAO appDataDAO; @Autowired protected AppSiteDAO appSiteDAO; @@ -139,11 +135,12 @@ public abstract class AbstractAppRuleDriver implements AppRuleDriver { Map filterCtx, String bubbleJsTemplate, String defaultSiteTemplate, - String siteJsInsertionVar) { + String siteJsInsertionVar, + boolean showIcon) { final RequestModifierConfig modConfig = requestModConfig(); final String replacement = DEFAULT_PREFIX_REPLACEMENT_WITH_MATCH + scriptOpen(filterRequest, modConfig.getScriptOpenNonce(), modConfig.getScriptOpenNoNonce()) - + getBubbleJs(filterRequest.getId(), filterCtx, bubbleJsTemplate, defaultSiteTemplate, siteJsInsertionVar) + + getBubbleJs(filterRequest.getId(), filterCtx, bubbleJsTemplate, defaultSiteTemplate, siteJsInsertionVar, showIcon) + getScriptClose(); final RegexReplacementFilter filter = new RegexReplacementFilter(getInsertionRegex(), replacement); @@ -162,20 +159,35 @@ public abstract class AbstractAppRuleDriver implements AppRuleDriver { Map filterCtx, String bubbleJsTemplate, String defaultSiteTemplate, - String siteJsInsertionVar) { + String siteJsInsertionVar, + boolean showIcon) { final Map ctx = getBubbleJsContext(requestId, filterCtx); if (!empty(siteJsInsertionVar) && !empty(defaultSiteTemplate)) { final String siteJs = HandlebarsUtil.apply(getHandlebars(), getSiteJsTemplate(defaultSiteTemplate), ctx); ctx.put(siteJsInsertionVar, siteJs); } - + if (showIcon) { + ctx.put(CTX_ICON_JS, HandlebarsUtil.apply(getHandlebars(), ICON_JS_TEMPLATE, ctx)); + } return HandlebarsUtil.apply(getHandlebars(), bubbleJsTemplate, ctx); } + public static final String CTX_JS_PREFIX = "JS_PREFIX"; + public static final String CTX_PAGE_PREFIX = "PAGE_PREFIX"; + public static final String CTX_BUBBLE_REQUEST_ID = "BUBBLE_REQUEST_ID"; + public static final String CTX_BUBBLE_DATA_ID = "BUBBLE_DATA_ID"; + public static final String CTX_BUBBLE_HOME = "BUBBLE_HOME"; + public static final String CTX_SITE = "SITE"; + public static final String CTX_ICON_JS = "ICON_JS"; + + private String getPagePrefix(String requestId) { return "__bubble_"+sha256_hex(requestId); } + private String getJsPrefix(String requestId) { return "__bubble_"+sha256_hex(requestId+"_"+getClass().getName()); } + protected Map getBubbleJsContext(String requestId, Map filterCtx) { final Map ctx = new HashMap<>(); - ctx.put(CTX_JS_PREFIX, AppRuleDriver.getJsPrefix(requestId)); + ctx.put(CTX_PAGE_PREFIX, getPagePrefix(requestId)); + ctx.put(CTX_JS_PREFIX, getJsPrefix(requestId)); ctx.put(CTX_BUBBLE_REQUEST_ID, requestId); ctx.put(CTX_BUBBLE_HOME, configuration.getPublicUriBase()); ctx.put(CTX_SITE, getSiteName(matcher)); diff --git a/bubble-server/src/main/java/bubble/rule/AppRuleDriver.java b/bubble-server/src/main/java/bubble/rule/AppRuleDriver.java index 5d67e806..765059ee 100644 --- a/bubble-server/src/main/java/bubble/rule/AppRuleDriver.java +++ b/bubble-server/src/main/java/bubble/rule/AppRuleDriver.java @@ -114,8 +114,6 @@ public interface AppRuleDriver { default Handlebars getHandlebars() { return null; } - static String getJsPrefix(String requestId) { return "__bubble_"+sha256_hex(requestId)+"_"; } - default String locateResource(String res) { if (!res.startsWith("@")) return res; final String prefix = getPackagePath(getClass()) + "/" + getClass().getSimpleName(); diff --git a/bubble-server/src/main/java/bubble/rule/RequestModifierRule.java b/bubble-server/src/main/java/bubble/rule/RequestModifierRule.java index afb44c01..4319940e 100644 --- a/bubble-server/src/main/java/bubble/rule/RequestModifierRule.java +++ b/bubble-server/src/main/java/bubble/rule/RequestModifierRule.java @@ -4,8 +4,14 @@ */ package bubble.rule; +import static org.cobbzilla.util.io.StreamUtil.stream2string; +import static org.cobbzilla.util.string.StringUtil.getPackagePath; + public interface RequestModifierRule { RequestModifierConfig getRequestModifierConfig (); + Class RMR = RequestModifierRule.class; + String ICON_JS_TEMPLATE = stream2string(getPackagePath(RMR)+"/"+ RMR.getSimpleName()+"_icon.js.hbs"); + } diff --git a/bubble-server/src/main/java/bubble/rule/bblock/BubbleBlockRuleDriver.java b/bubble-server/src/main/java/bubble/rule/bblock/BubbleBlockRuleDriver.java index 3a741d93..52805821 100644 --- a/bubble-server/src/main/java/bubble/rule/bblock/BubbleBlockRuleDriver.java +++ b/bubble-server/src/main/java/bubble/rule/bblock/BubbleBlockRuleDriver.java @@ -40,6 +40,7 @@ import static org.cobbzilla.util.http.HttpContentTypes.isHtml; import static org.cobbzilla.util.io.StreamUtil.stream2string; 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; @Slf4j @@ -286,6 +287,7 @@ public class BubbleBlockRuleDriver extends TrafficAnalyticsRuleDriver implements } public static final String FILTER_CTX_DECISION = "decision"; + public static final String BLOCK_STATS_JS = "BLOCK_STATS_JS"; @Override public InputStream doFilterResponse(FilterHttpRequest filterRequest, InputStream in) { @@ -333,24 +335,24 @@ public class BubbleBlockRuleDriver extends TrafficAnalyticsRuleDriver implements return in; } - if (!bubbleBlockConfig.inPageBlocks() && !bubbleBlockConfig.showStats()) { + final boolean showStats = bubbleBlockConfig.showStats(); + if (!bubbleBlockConfig.inPageBlocks() && !showStats) { if (log.isInfoEnabled()) log.info(prefix + "SEND: both inPageBlocks and showStats are false, returning as-is"); return in; } - if (bubbleBlockConfig.inPageBlocks() && bubbleBlockConfig.showStats()) { - return filterInsertJs(in, filterRequest, filterCtx, BUBBLE_JS_BOTH_TEMPLATE, null, null); + if (bubbleBlockConfig.inPageBlocks() && showStats) { + return filterInsertJs(in, filterRequest, filterCtx, BUBBLE_JS_TEMPLATE, BUBBLE_JS_STATS_TEMPLATE, BLOCK_STATS_JS, showStats); } if (bubbleBlockConfig.inPageBlocks()) { - return filterInsertJs(in, filterRequest, filterCtx, BUBBLE_JS_TEMPLATE, null, null); + return filterInsertJs(in, filterRequest, filterCtx, BUBBLE_JS_TEMPLATE, EMPTY, BLOCK_STATS_JS, showStats); } - log.warn(prefix+"doFilterResponse: inserting JS for stats..."); - return filterInsertJs(in, filterRequest, filterCtx, BUBBLE_JS_STATS_TEMPLATE, null, null); + log.warn(prefix+"inserting JS for stats..."); + return filterInsertJs(in, filterRequest, filterCtx, BUBBLE_JS_STATS_TEMPLATE, null, null, showStats); } public static final Class BB = BubbleBlockRuleDriver.class; public static final String BUBBLE_JS_TEMPLATE = stream2string(getPackagePath(BB)+"/"+ BB.getSimpleName()+".js.hbs"); public static final String BUBBLE_JS_STATS_TEMPLATE = stream2string(getPackagePath(BB)+"/"+ BB.getSimpleName()+"_stats.js.hbs"); - public static final String BUBBLE_JS_BOTH_TEMPLATE = BUBBLE_JS_TEMPLATE + "\n\n" + BUBBLE_JS_STATS_TEMPLATE; private static final String CTX_BUBBLE_SELECTORS = "BUBBLE_SELECTORS_JSON"; private static final String CTX_BUBBLE_BLACKLIST = "BUBBLE_BLACKLIST_JSON"; diff --git a/bubble-server/src/main/java/bubble/rule/social/block/JsUserBlockerRuleDriver.java b/bubble-server/src/main/java/bubble/rule/social/block/JsUserBlockerRuleDriver.java index 0a5f9bd1..387c8897 100644 --- a/bubble-server/src/main/java/bubble/rule/social/block/JsUserBlockerRuleDriver.java +++ b/bubble-server/src/main/java/bubble/rule/social/block/JsUserBlockerRuleDriver.java @@ -8,7 +8,6 @@ import bubble.resources.stream.FilterHttpRequest; import bubble.rule.AbstractAppRuleDriver; import bubble.rule.RequestModifierConfig; import bubble.rule.RequestModifierRule; -import bubble.rule.bblock.BubbleBlockConfig; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @@ -16,7 +15,6 @@ import java.io.InputStream; import static org.cobbzilla.util.http.HttpContentTypes.isHtml; import static org.cobbzilla.util.io.StreamUtil.stream2string; -import static org.cobbzilla.util.json.JsonUtil.json; import static org.cobbzilla.util.string.StringUtil.getPackagePath; @Slf4j @@ -37,7 +35,7 @@ public class JsUserBlockerRuleDriver extends AbstractAppRuleDriver implements Re @Override public InputStream doFilterResponse(FilterHttpRequest filterRequest, InputStream in) { if (!isHtml(filterRequest.getContentType())) return in; - log.warn("doFilterResponse: inserting JS, getRequestModifierConfig()="+json(getRequestModifierConfig())); - return filterInsertJs(in, filterRequest, null, BUBBLE_JS_TEMPLATE, getDefaultSiteJsTemplate(), CTX_APPLY_BLOCKS_JS); + log.warn("doFilterResponse("+filterRequest.getId()+"): inserting JS"); + return filterInsertJs(in, filterRequest, null, BUBBLE_JS_TEMPLATE, getDefaultSiteJsTemplate(), CTX_APPLY_BLOCKS_JS, true); } } diff --git a/bubble-server/src/main/resources/bubble/rule/RequestModifierRule_icon.js.hbs b/bubble-server/src/main/resources/bubble/rule/RequestModifierRule_icon.js.hbs new file mode 100644 index 00000000..46856393 --- /dev/null +++ b/bubble-server/src/main/resources/bubble/rule/RequestModifierRule_icon.js.hbs @@ -0,0 +1,33 @@ + +if (typeof {{PAGE_PREFIX}}_icon_status === 'undefined') { + let {{PAGE_PREFIX}}_doc_ready = false; + const {{PAGE_PREFIX}}_interval = 50; + + {{PAGE_PREFIX}}_icon_status = []; + + function {{PAGE_PREFIX}}_onReady(callback) { + const intervalId = window.setInterval(function() { + if (document.getElementsByTagName('body')[0] !== undefined) { + {{PAGE_PREFIX}}_doc_ready = true; + window.clearInterval(intervalId); + callback.call(this); + } + }, {{PAGE_PREFIX}}_interval); + } + + {{PAGE_PREFIX}}_onReady(function() { + const controlDivId = '{{PAGE_PREFIX}}_controlDiv'; + let bubbleControlDiv = document.getElementById(controlDivId); + if (bubbleControlDiv === null) { + bubbleControlDiv = document.createElement('div'); + bubbleControlDiv.id = controlDivId; + bubbleControlDiv.style.position = 'fixed'; + bubbleControlDiv.style.bottom = '0'; + bubbleControlDiv.style.right = '0'; + document.getElementsByTagName('body')[0].appendChild(bubbleControlDiv); + } + for (let i=0; i<{{PAGE_PREFIX}}_icon_status.length; i++) { + bubbleControlDiv.innerHTML = bubbleControlDiv.innerHTML + {{PAGE_PREFIX}}_icon_status[i].iconHtml; + } + }); +} \ No newline at end of file diff --git a/bubble-server/src/main/resources/bubble/rule/bblock/BubbleBlockRuleDriver.js.hbs b/bubble-server/src/main/resources/bubble/rule/bblock/BubbleBlockRuleDriver.js.hbs index 49d7c8e1..61515be1 100644 --- a/bubble-server/src/main/resources/bubble/rule/bblock/BubbleBlockRuleDriver.js.hbs +++ b/bubble-server/src/main/resources/bubble/rule/bblock/BubbleBlockRuleDriver.js.hbs @@ -326,3 +326,5 @@ function {{JS_PREFIX}}_process_filters() { {{JS_PREFIX}}_process_filters(); window.setInterval({{JS_PREFIX}}_process_filters, {{JS_PREFIX}}_idle_interval); }); + +{{{BLOCK_STATS_JS}}} \ No newline at end of file diff --git a/bubble-server/src/main/resources/bubble/rule/bblock/BubbleBlockRuleDriver_stats.js.hbs b/bubble-server/src/main/resources/bubble/rule/bblock/BubbleBlockRuleDriver_stats.js.hbs index c78498fc..0e9d5113 100644 --- a/bubble-server/src/main/resources/bubble/rule/bblock/BubbleBlockRuleDriver_stats.js.hbs +++ b/bubble-server/src/main/resources/bubble/rule/bblock/BubbleBlockRuleDriver_stats.js.hbs @@ -1,3 +1,10 @@ // // block stats js goes here // +{{{ICON_JS}}} + +{{PAGE_PREFIX}}_icon_status.push({ + jsPrefix: '{{JS_PREFIX}}', + iconHtml: '
' +}); +console.log("BubbleBlock pushed icon, {{PAGE_PREFIX}}_icon_status="+JSON.stringify({{PAGE_PREFIX}}_icon_status)); \ No newline at end of file diff --git a/bubble-server/src/main/resources/bubble/rule/social/block/JsUserBlockerRuleDriver.js.hbs b/bubble-server/src/main/resources/bubble/rule/social/block/JsUserBlockerRuleDriver.js.hbs index aa88cbd7..00857ade 100644 --- a/bubble-server/src/main/resources/bubble/rule/social/block/JsUserBlockerRuleDriver.js.hbs +++ b/bubble-server/src/main/resources/bubble/rule/social/block/JsUserBlockerRuleDriver.js.hbs @@ -1,19 +1,10 @@ let {{JS_PREFIX}}_blocked_users = null; -let {{JS_PREFIX}}_doc_ready = false; const {{JS_PREFIX}}_request_id = '{{BUBBLE_REQUEST_ID}}'; + +let {{JS_PREFIX}}_doc_ready = false; const {{JS_PREFIX}}_interval = 50; const {{JS_PREFIX}}_idle_interval = 1000; -function {{JS_PREFIX}}_onReady(callback) { - const intervalId = window.setInterval(function() { - if (document.getElementsByTagName('body')[0] !== undefined) { - {{JS_PREFIX}}_doc_ready = true; - window.clearInterval(intervalId); - callback.call(this); - } - }, {{JS_PREFIX}}_interval); -} - function {{JS_PREFIX}}_fetch_blocks (do_apply) { const requestOptions = { method: 'GET' }; const blocked_users_url = '/__bubble/api/filter/data/{{BUBBLE_DATA_ID}}/read'; @@ -60,16 +51,10 @@ function {{JS_PREFIX}}_block_user (author) { {{{APPLY_BLOCKS_JS}}} -{{JS_PREFIX}}_onReady(function() { - const controlDivId = '{{JS_PREFIX}}_controlDiv'; - let bubbleControlDiv = document.getElementById(controlDivId); - if (bubbleControlDiv === null) { - bubbleControlDiv = document.createElement('div'); - bubbleControlDiv.id = controlDivId; - bubbleControlDiv.style.position = 'fixed'; - bubbleControlDiv.style.bottom = '0'; - bubbleControlDiv.style.right = '0'; - document.getElementsByTagName('body')[0].appendChild(bubbleControlDiv); - } - bubbleControlDiv.innerHTML = bubbleControlDiv.innerHTML + '
'; +{{{ICON_JS}}} + +{{PAGE_PREFIX}}_icon_status.push({ + jsPrefix: '{{JS_PREFIX}}', + iconHtml: '
' }); +console.log("JsUserBlocker pushed icon, {{PAGE_PREFIX}}_icon_status="+JSON.stringify({{PAGE_PREFIX}}_icon_status)); \ No newline at end of file