From 8d09cc4e5005b0a1c8bf41918058d2c21c2f773e Mon Sep 17 00:00:00 2001 From: Adam Miller Date: Tue, 7 Oct 2025 11:04:12 -0700 Subject: [PATCH] feat: Pass along script tag attributes to JS extractor for configurable rejection. --- .../extractor/ConfigurableExtractorJS.java | 37 ++++++++++++++++++- .../modules/extractor/ExtractorHTML.java | 21 ++++++++++- .../modules/extractor/ExtractorJS.java | 4 ++ 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/modules/src/main/java/org/archive/modules/extractor/ConfigurableExtractorJS.java b/modules/src/main/java/org/archive/modules/extractor/ConfigurableExtractorJS.java index 9cdc7fc4..b506f2fc 100644 --- a/modules/src/main/java/org/archive/modules/extractor/ConfigurableExtractorJS.java +++ b/modules/src/main/java/org/archive/modules/extractor/ConfigurableExtractorJS.java @@ -126,7 +126,31 @@ public class ConfigurableExtractorJS extends ExtractorJS { public void addRejectRelativeIgnoreList(String ignoreString) { rejectRelativeIgnoreSet.add(ignoreString); } - + + + /** + * List of regular expressions that will block extraction if matched against a script tag attribute. + * When script blocks are extracted from HTML, the tag attributes are passed as the attributeContext parameter + * to considerStrings. If any of the patterns on this list match the attributeContext, then the script block is not + * processed. + * This can be used to block processing of script blocks + */ + private List rejectScriptAttributeRegexList = new ArrayList<>(); + private List rejectScriptAttributeRegexListPatterns = new ArrayList<>(); + + public List getRejectScriptAttributeRegexList() { + return rejectScriptAttributeRegexList; + } + public void setRejectScriptAttributeRegexList(List patterns) { + rejectScriptAttributeRegexList = patterns; + rejectScriptAttributeRegexListPatterns = new ArrayList<>(); + for (String p : patterns) { + rejectScriptAttributeRegexListPatterns.add(Pattern.compile(p, Pattern.CASE_INSENSITIVE)); + } + } + public void addRejectScriptAttributeRegex(String pattern) { + rejectScriptAttributeRegexListPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE)); + } @Override protected boolean shouldAddUri(CrawlURI curi, String candidate) { @@ -181,5 +205,14 @@ public class ConfigurableExtractorJS extends ExtractorJS { return false; } - + public long considerStrings(Extractor ext, + CrawlURI curi, CharSequence cs, String attributeContext) { + if(!attributeContext.isEmpty()) + for(Pattern p : rejectScriptAttributeRegexListPatterns) { + if(p.matcher(attributeContext).matches()) { + return 0; + } + } + return super.considerStrings(ext, curi, cs, attributeContext); + } } diff --git a/modules/src/main/java/org/archive/modules/extractor/ExtractorHTML.java b/modules/src/main/java/org/archive/modules/extractor/ExtractorHTML.java index 2be77f06..3562611d 100644 --- a/modules/src/main/java/org/archive/modules/extractor/ExtractorHTML.java +++ b/modules/src/main/java/org/archive/modules/extractor/ExtractorHTML.java @@ -721,7 +721,6 @@ public class ExtractorHTML extends ContentExtractor implements InitializingBean } } - /** * Extract the (java)script source in the given CharSequence. * @@ -735,6 +734,21 @@ public class ExtractorHTML extends ContentExtractor implements InitializingBean } } + /** + * Extract the (java)script source in the given CharSequence. + * + * @param curi source CrawlURI + * @param cs CharSequence of javascript code + * @param attributeContext attributes of the tag from which the script + * was extracted (e.g. "onload", "onclick", "data-", etc.) + */ + protected void processScriptCode(CrawlURI curi, CharSequence cs, String attributeContext) { + if (getExtractorJS() != null && getExtractJavascript()) { + numberOfLinksExtracted.addAndGet( + getExtractorJS().considerStrings(this, curi, cs, attributeContext)); + } + } + static final String JAVASCRIPT = "(?i)^javascript:.*"; /** @@ -1041,6 +1055,11 @@ public class ExtractorHTML extends ContentExtractor implements InitializingBean // then, apply best-effort string-analysis heuristics // against any code present (false positives are OK) + if(endOfOpenTag > 6) { + String attributes = sequence.subSequence(6, endOfOpenTag).toString().strip(); + processScriptCode( + curi, sequence.subSequence(endOfOpenTag, sequence.length()), attributes); + } processScriptCode( curi, sequence.subSequence(endOfOpenTag, sequence.length())); } diff --git a/modules/src/main/java/org/archive/modules/extractor/ExtractorJS.java b/modules/src/main/java/org/archive/modules/extractor/ExtractorJS.java index 530e4c05..703f313b 100644 --- a/modules/src/main/java/org/archive/modules/extractor/ExtractorJS.java +++ b/modules/src/main/java/org/archive/modules/extractor/ExtractorJS.java @@ -137,6 +137,10 @@ public class ExtractorJS extends ContentExtractor { CrawlURI curi, CharSequence cs) { return considerStrings(ext, curi, cs, false); } + public long considerStrings(Extractor ext, + CrawlURI curi, CharSequence cs, String attributeContext) { + return considerStrings(ext, curi, cs, false); + } public long considerStrings(Extractor ext, CrawlURI curi, CharSequence cs, boolean handlingJSFile) {