aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/img/filtering-overview-plain.svg290
-rw-r--r--platform/chromium/manifest.json2
-rw-r--r--src/background.html2
-rw-r--r--src/css/logger-ui.css206
-rw-r--r--src/js/dyna-rules.js12
-rw-r--r--src/js/dynamic-net-filtering.js25
-rw-r--r--src/js/logger-ui.js333
-rw-r--r--src/js/logger.js19
-rw-r--r--src/js/messaging.js144
-rw-r--r--src/js/pagestore.js38
-rw-r--r--src/js/start.js6
-rw-r--r--src/js/storage.js8
-rw-r--r--src/js/tab.js3
-rw-r--r--src/js/traffic.js10
-rw-r--r--src/js/ublock.js50
-rw-r--r--src/js/url-net-filtering.js391
-rw-r--r--src/logger-ui.html13
17 files changed, 1313 insertions, 239 deletions
diff --git a/doc/img/filtering-overview-plain.svg b/doc/img/filtering-overview-plain.svg
index 9bf6278..53cd343 100644
--- a/doc/img/filtering-overview-plain.svg
+++ b/doc/img/filtering-overview-plain.svg
@@ -9,7 +9,7 @@
xmlns="http://www.w3.org/2000/svg"
version="1.1"
width="732"
- height="1540.3398"
+ height="1740.3398"
id="svg2">
<defs
id="defs4">
@@ -517,6 +517,66 @@
id="path11883"
style="fill:#000000;fill-rule:evenodd;stroke:#000000;stroke-width:1pt" />
</marker>
+ <marker
+ refX="0"
+ refY="0"
+ orient="auto"
+ id="TriangleOutMW-2"
+ style="overflow:visible">
+ <path
+ d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+ transform="scale(0.4,0.4)"
+ id="path9001-1"
+ style="fill:#00aa00;fill-rule:evenodd;stroke:#00aa00;stroke-width:1pt" />
+ </marker>
+ <marker
+ refX="0"
+ refY="0"
+ orient="auto"
+ id="DotMc-3"
+ style="overflow:visible">
+ <path
+ d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
+ transform="matrix(0.4,0,0,0.4,2.96,0.4)"
+ id="path10345-9"
+ style="fill:#cc0000;fill-rule:evenodd;stroke:#cc0000;stroke-width:1pt" />
+ </marker>
+ <marker
+ refX="0"
+ refY="0"
+ orient="auto"
+ id="TriangleOutM-03"
+ style="overflow:visible">
+ <path
+ d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+ transform="scale(0.4,0.4)"
+ id="path4034-0"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt" />
+ </marker>
+ <marker
+ refX="0"
+ refY="0"
+ orient="auto"
+ id="DiamondSPd-4"
+ style="overflow:visible">
+ <path
+ d="M 0,-7.0710768 -7.0710894,0 0,7.0710589 7.0710462,0 0,-7.0710768 z"
+ transform="scale(0.2,0.2)"
+ id="path11517-1"
+ style="fill:#b0b0b0;fill-rule:evenodd;stroke:#b0b0b0;stroke-width:1pt" />
+ </marker>
+ <marker
+ refX="0"
+ refY="0"
+ orient="auto"
+ id="TriangleOutM-9"
+ style="overflow:visible">
+ <path
+ d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+ transform="scale(0.4,0.4)"
+ id="path4034-2"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt" />
+ </marker>
</defs>
<metadata
id="metadata7">
@@ -603,15 +663,15 @@
rx="0.5"
ry="0.49999997"
x="240"
- y="-97.637817"
+ y="102.36218"
id="rect3783-4"
style="fill:#ffeeaa;fill-opacity:1;fill-rule:nonzero;stroke:none" />
<path
- d="m 280,-857.63782 -180,0 0,1200"
+ d="m 280,-857.63782 -180,0 0,1399.99999"
id="path4799"
style="fill:none;stroke:#b0b0b0;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path
- d="m 710,-507.63782 c 0,346.66667 0,623.33333 0,970 l -280,0"
+ d="m 710,-507.63782 c 0,346.66667 0,823.33332 0,1169.99999 l -280,0"
id="path4987"
style="fill:none;stroke:#00aa00;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:url(#DotM7);marker-end:url(#TriangleOutM-2n)" />
<text
@@ -628,28 +688,28 @@
id="tspan7956">whitelisted?</tspan></text>
<text
x="390"
- y="-47.637821"
+ y="152.36218"
id="text5171-7"
xml:space="preserve"
style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"><tspan
x="390"
- y="-47.637821"
+ y="152.36218"
id="tspan5384">local dynamic</tspan><tspan
x="390"
- y="-17.637821"
+ y="182.36218"
id="tspan5388">filtering rule?</tspan></text>
<path
- d="m 519.99999,-57.637827 180,0"
+ d="m 519.99999,142.36217 180,0"
id="path5390"
style="opacity:0.95999995;fill:none;stroke:#00aa00;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#TriangleOutMW)" />
<text
x="550"
- y="-67.637817"
+ y="132.36218"
id="text5574"
xml:space="preserve"
style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"><tspan
x="550"
- y="-67.637817"
+ y="132.36218"
id="tspan5576">allow</tspan></text>
<path
d="m 420,-607.63782 0,100"
@@ -665,26 +725,26 @@
y="-357.86438"
id="tspan5948">no</tspan></text>
<text
- x="550"
- y="2.36218"
+ x="548.48438"
+ y="201.3231"
id="text5946-2"
xml:space="preserve"
style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"><tspan
- x="550"
- y="2.36218"
+ x="548.48438"
+ y="201.3231"
id="tspan5948-1">noop</tspan></text>
<path
- d="m 610,-507.63782 c 0,173.33333 0,596.66667 0,770 l -180,0"
+ d="m 610,-507.63782 c 0,173.33333 0,796.66666 0,969.99999 l -180,0"
id="path5390-8"
style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:url(#DotM);marker-end:url(#TriangleOutM)" />
<text
x="440"
- y="42.362179"
+ y="242.36218"
id="text5946-8"
xml:space="preserve"
style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"><tspan
x="440"
- y="42.362179"
+ y="242.36218"
id="tspan5948-6">no</tspan></text>
<rect
width="280"
@@ -692,59 +752,59 @@
rx="0.5"
ry="0.49999997"
x="240"
- y="102.36218"
+ y="302.36218"
id="rect3783-4-3"
style="fill:#ffeeaa;fill-opacity:1;fill-rule:nonzero;stroke:none" />
<path
- d="M 419.99999,22.362173 420,92.36218"
+ d="M 419.99999,222.36217 420,292.36218"
id="path5762-6"
style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-end:url(#TriangleOutM)" />
<text
x="390"
- y="152.36217"
+ y="352.36218"
id="text5171-7-9"
xml:space="preserve"
style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"><tspan
x="390"
- y="152.36217"
+ y="352.36218"
id="tspan5384-4">global dynamic</tspan><tspan
x="390"
- y="182.36217"
+ y="382.36218"
id="tspan5388-3">filtering rule?</tspan></text>
<path
- d="m 519.89843,142.13559 180.10156,0.22658"
+ d="m 519.89843,342.13559 180.10156,0.22658"
id="path5390-1"
style="fill:none;stroke:#00aa00;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#TriangleOutM9)" />
<text
x="550"
- y="132.36218"
+ y="332.36218"
id="text5574-8"
xml:space="preserve"
style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"><tspan
x="550"
- y="132.36218"
+ y="332.36218"
id="tspan5576-4">allow</tspan></text>
<text
- x="550"
- y="202.36218"
+ x="548.48438"
+ y="401.32312"
id="text5946-2-9"
xml:space="preserve"
style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"><tspan
- x="550"
- y="202.36218"
+ x="548.48438"
+ y="401.32312"
id="tspan5948-1-9">noop</tspan></text>
<path
- d="M 519.99999,182.36216 600,182.36218"
+ d="M 519.99999,382.36216 600,382.36218"
id="path5390-8-2"
style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#TriangleOutM-6)" />
<text
x="440"
- y="242.36218"
+ y="442.36218"
id="text5946-8-3"
xml:space="preserve"
style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"><tspan
x="440"
- y="242.36218"
+ y="442.36218"
id="tspan6526">no</tspan></text>
<rect
width="280"
@@ -752,24 +812,24 @@
rx="0.5"
ry="0.49999997"
x="240"
- y="302.36218"
+ y="502.36218"
id="rect3783-4-31"
style="fill:#ffeeaa;fill-opacity:1;fill-rule:nonzero;stroke:none" />
<path
- d="M 419.99999,222.36216 420,292.36218"
+ d="M 419.99999,422.36216 420,492.36218"
id="path5762-6-3"
style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#TriangleOutM)" />
<text
x="380"
- y="362.36218"
+ y="562.36218"
id="text5171-7-1"
xml:space="preserve"
style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"><tspan
x="380"
- y="362.36218"
+ y="562.36218"
id="tspan5388-5">static filtering?</tspan></text>
<path
- d="m 99.999995,-57.637827 139.999995,0"
+ d="m 99.999995,142.36217 139.999995,0"
id="path8567"
style="fill:none;stroke:#b0b0b0;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#DiamondSPd)" />
<path
@@ -783,59 +843,54 @@
rx="0.5"
ry="0.49999997"
x="240"
- y="-297.63782"
+ y="-97.637817"
id="rect3783-7"
style="fill:#ffeeaa;fill-opacity:1;fill-rule:nonzero;stroke:none" />
- <path
- d="m 420,-377.63782 0,70"
- id="path5762"
- style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#TriangleOutM)" />
<text
x="380"
- y="-247.63782"
+ y="-47.637817"
id="text5171-8"
xml:space="preserve"
style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"><tspan
x="380"
- y="-247.63782"
+ y="-47.637817"
id="tspan5175-2"
style="font-style:italic;-inkscape-font-specification:Sans Italic">advanced user</tspan><tspan
x="380"
- y="-217.63782"
+ y="-17.637817"
id="tspan5410">mode?</tspan></text>
<text
x="440"
- y="-157.63782"
+ y="42.362183"
id="text5946-9"
xml:space="preserve"
style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"><tspan
x="440"
- y="-157.63782"
+ y="42.362183"
id="tspan5948-62">yes</tspan></text>
<path
- d="m 420,-177.63782 0,70"
+ d="m 420,22.36218 0,70"
id="path5762-0"
style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#TriangleOutM)" />
<path
- d="m 520,-17.63782 80,0"
+ d="m 520,182.36218 80,0"
id="path5390-5"
style="opacity:0.95999995;fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#TriangleOutM)" />
<text
- x="540"
- y="-197.63782"
+ x="538.51562"
+ y="1.3231113"
id="text5946-7"
xml:space="preserve"
style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"><tspan
- x="540"
- y="-197.63782"
+ x="538.51562"
+ y="1.3231113"
id="tspan5948-9">no</tspan></text>
<path
- d="m 520,730 80,0"
- transform="translate(0,-947.63782)"
+ d="m 520,-17.63782 80,0"
id="path5695"
style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#TriangleOutM-6)" />
<path
- d="m 100,342.36218 140,0"
+ d="m 100,542.36218 140,0"
id="path8567-7"
style="fill:none;stroke:#b0b0b0;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#DiamondSOI)" />
<path
@@ -844,17 +899,17 @@
id="path6779"
style="fill:none;stroke:#00aa00;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#TriangleOutM-6b)" />
<path
- d="m 420,422.36218 0,150"
+ d="m 420,622.36218 0,150"
id="path5762-6-3-1"
style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#TriangleOutMe9)" />
<text
x="460"
- y="442.36218"
+ y="642.36218"
id="text5946-8-3-5"
xml:space="preserve"
style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"><tspan
x="460"
- y="442.36218"
+ y="642.36218"
id="tspan6526-8">no filter</tspan></text>
<text
x="180"
@@ -887,65 +942,65 @@
y="-847.63782"
id="tspan5175-3-2">URL of page</tspan></text>
<path
- d="m 340,22.36218 0,40"
+ d="m 340,222.36218 0,40"
id="path5762-6-9"
style="fill:none;stroke:#cc0000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-end:url(#DotMc);display:inline" />
<text
x="310"
- y="42.362179"
+ y="242.36218"
id="text5946-8-7"
xml:space="preserve"
style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"><tspan
x="310"
- y="42.362179"
+ y="242.36218"
id="tspan5948-6-0">block</tspan></text>
<path
- d="m 340,222.36218 0,40"
+ d="m 340,422.36218 0,40"
id="path5762-6-9-0"
style="fill:none;stroke:#cc0000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-end:url(#DotMA);display:inline" />
<text
x="310"
- y="242.36218"
+ y="442.36218"
id="text5946-8-7-3"
xml:space="preserve"
style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"><tspan
x="310"
- y="242.36218"
+ y="442.36218"
id="tspan5948-6-0-3">block</tspan></text>
<path
- d="m 520,342.36218 180,0"
+ d="m 520,542.36218 180,0"
id="path5390-1-2"
style="fill:none;stroke:#00aa00;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#TriangleOutMx);display:inline" />
<text
x="590"
- y="332.36218"
+ y="532.36218"
id="text5946-2-9-9"
xml:space="preserve"
style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"><tspan
x="590"
- y="332.36218"
+ y="532.36218"
id="tspan5948-1-9-5">exception filter</tspan></text>
<path
- d="m 340,422.36218 0,40"
+ d="m 340,622.36218 0,40"
id="path5762-6-9-0-9"
style="fill:none;stroke:#cc0000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-end:url(#DotMf);display:inline" />
<text
x="290"
- y="442.36218"
+ y="642.36218"
id="text5946-8-7-3-2"
xml:space="preserve"
style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"><tspan
x="290"
- y="442.36218"
+ y="642.36218"
id="tspan5948-6-0-3-0">block filter</tspan></text>
<text
x="420"
- y="602.36218"
+ y="802.36218"
id="text5946-8-7-3-2-4"
xml:space="preserve"
style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"><tspan
x="420"
- y="602.36218"
+ y="802.36218"
id="tspan5948-6-0-3-0-2">remote server</tspan></text>
<text
x="540"
@@ -957,8 +1012,7 @@
y="-467.63782"
id="tspan5948-62-1">yes</tspan></text>
<path
- d="m 750,1450 -690,0"
- transform="translate(0,-947.63782)"
+ d="m 750,702.36218 -690,0"
id="path12147"
style="fill:#cccccc;stroke:#808080;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:8, 8;stroke-dashoffset:0" />
<path
@@ -966,13 +1020,91 @@
id="path12147-5"
style="fill:#cccccc;stroke:#808080;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:8, 8;stroke-dashoffset:0;display:inline" />
<text
- x="638.15234"
- y="-869.40344"
+ x="620"
+ y="-867.63782"
id="text5171-77-67"
xml:space="preserve"
style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"><tspan
- x="638.15234"
- y="-869.40344"
+ x="620"
+ y="-867.63782"
id="tspan5175-3-1">your browser</tspan></text>
+ <rect
+ width="280"
+ height="120"
+ rx="0.5"
+ ry="0.49999997"
+ x="240"
+ y="-297.63782"
+ id="rect3783-7-4"
+ style="fill:#ffeeaa;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline" />
+ <path
+ d="m 420,-377.63782 0,70"
+ id="path5762"
+ style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#TriangleOutM)" />
+ <text
+ x="380"
+ y="-247.63783"
+ id="text5171-8-9"
+ xml:space="preserve"
+ style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"><tspan
+ x="380"
+ y="-247.63783"
+ id="tspan5410-4">url filtering rule?</tspan></text>
+ <path
+ d="m 520,-257.63783 180,0"
+ id="path5390-2"
+ style="opacity:0.95999995;fill:none;stroke:#00aa00;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#TriangleOutMW);display:inline" />
+ <text
+ x="550"
+ y="-267.63782"
+ id="text5574-7"
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"><tspan
+ x="550"
+ y="-267.63782"
+ id="tspan5576-8">allow</tspan></text>
+ <path
+ d="m 340,-177.63783 0,40"
+ id="path5762-6-9-9"
+ style="fill:none;stroke:#cc0000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-end:url(#DotMc);display:inline" />
+ <text
+ x="310"
+ y="-157.63783"
+ id="text5946-8-7-7"
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"><tspan
+ x="310"
+ y="-157.63783"
+ id="tspan5948-6-0-4">block</tspan></text>
+ <text
+ x="440.89844"
+ y="-157.8644"
+ id="text5946-5"
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"><tspan
+ x="440.89844"
+ y="-157.8644"
+ id="tspan5948-8">no</tspan></text>
+ <path
+ d="m 420,-177.63783 0,70"
+ id="path5762-3"
+ style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#TriangleOutM);display:inline" />
+ <path
+ d="m 100,-257.63782 140,0"
+ id="path8567-2"
+ style="fill:none;stroke:#b0b0b0;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#DiamondSPd);display:inline" />
+ <text
+ x="548.48438"
+ y="-198.6769"
+ id="text5946-2-8"
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"><tspan
+ x="548.48438"
+ y="-198.6769"
+ id="tspan5948-1-5">noop</tspan></text>
+ <path
+ d="m 520,-217.63783 80,0"
+ id="path5390-5-3"
+ style="opacity:0.95999995;fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#TriangleOutM);display:inline" />
</g>
</svg>
diff --git a/platform/chromium/manifest.json b/platform/chromium/manifest.json
index fbdc76c..be29dbf 100644
--- a/platform/chromium/manifest.json
+++ b/platform/chromium/manifest.json
@@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "uBlock Origin",
- "version": "0.9.7.5",
+ "version": "0.9.7.6",
"default_locale": "en",
"description": "__MSG_extShortDesc__",
diff --git a/src/background.html b/src/background.html
index 65b6ea0..786cd81 100644
--- a/src/background.html
+++ b/src/background.html
@@ -17,6 +17,7 @@
<script src="js/assets.js"></script>
<script src="js/dynamic-net-filtering.js"></script>
<script src="js/static-net-filtering.js"></script>
+<script src="js/url-net-filtering.js"></script>
<script src="js/cosmetic-filtering.js"></script>
<script src="js/hnswitches.js"></script>
<script src="js/ublock.js"></script>
@@ -28,7 +29,6 @@
<script src="js/tab.js"></script>
<script src="js/traffic.js"></script>
<script src="js/contextmenu.js"></script>
-<script src="js/mirrors.js"></script>
<script src="js/start.js"></script>
</body>
</html>
diff --git a/src/css/logger-ui.css b/src/css/logger-ui.css
index 00b8f9b..bb620aa 100644
--- a/src/css/logger-ui.css
+++ b/src/css/logger-ui.css
@@ -106,25 +106,25 @@ body.f table tr.f {
display: none;
}
-#content table tr.cat_info {
+#content tr.cat_info {
color: #00f;
}
-#content table tr.blocked {
+#content tr.blocked {
background-color: rgba(192, 0, 0, 0.1);
}
-body.colorBlind #content table tr.blocked {
+body.colorBlind #content tr.blocked {
background-color: rgba(0, 19, 110, 0.1);
}
-#content table tr.allowed {
+#content tr.allowed {
background-color: rgba(0, 160, 0, 0.1);
}
-body.colorBlind #content table tr.allowed {
+body.colorBlind #content tr.allowed {
background-color: rgba(255, 194, 57, 0.1)
}
-#content table tr.cosmetic {
+#content tr.cb {
background-color: rgba(255, 255, 0, 0.1);
}
-#content table tr.maindoc {
+#content tr.maindoc {
background-color: #666;
color: white;
text-align: center;
@@ -140,13 +140,13 @@ body #content td {
word-break: break-all;
word-wrap: break-word;
}
-#content table tr td {
+#content tr td {
border-top: 1px solid #ccc;
}
-#content table tr td:first-of-type {
+#content tr td:first-of-type {
border-left: none;
}
-#content table tr td:last-of-type {
+#content tr td:last-of-type {
border-right: none;
}
body.compactView #content td {
@@ -155,56 +155,63 @@ body.compactView #content td {
white-space: nowrap;
}
-#content table tr td:nth-of-type(1) {
+#content tr td:nth-of-type(1) {
text-align: right;
white-space: nowrap;
}
-#content table tr td:nth-of-type(2) {
+#content tr td:nth-of-type(2) {
text-align: center;
white-space: nowrap;
}
-#content table tr.tab_bts > td:nth-of-type(2):before {
+#content tr.tab_bts > td:nth-of-type(2):before {
content: '\f070';
font: 1em FontAwesome;
}
-#content table tr.tab:not(.canMtx) {
+#content tr.tab:not(.canMtx) {
opacity: 0.3;
}
-#content table tr.tab:not(.canMtx):hover {
+#content tr.tab:not(.canMtx):hover {
opacity: 0.7;
}
-#content table tr.tab:not(.canMtx) > td:nth-of-type(2):before {
+#content tr.tab:not(.canMtx) > td:nth-of-type(2):before {
content: '\f00d';
font: 1em FontAwesome;
}
-body:not(.popupOn) #content table tr.canMtx td:nth-of-type(2) {
+body:not(.popupOn) #content tr.canMtx td:nth-of-type(2) {
cursor: zoom-in;
}
-body:not(.popupOn) #content table tr.canMtx td:nth-of-type(2):hover {
+body:not(.popupOn) #content tr.canMtx td:nth-of-type(2):hover {
background: #ccc;
}
-#content table tr.cat_net td:nth-of-type(3),
-#content table tr.cat_cosmetic td:nth-of-type(3) {
+#content tr.cat_net td:nth-of-type(3),
+#content tr.cat_cosmetic td:nth-of-type(3) {
font: 12px monospace;
text-align: center;
white-space: nowrap;
}
-#content table tr.cat_net td:nth-of-type(6) > span > b {
+#content tr.cat_net td:nth-of-type(3) {
+ cursor: pointer;
+ position: relative;
+ }
+#content tr.cat_net td:nth-of-type(3):hover {
+ background: #ccc;
+ }
+#content tr.cat_net td:nth-of-type(6) > span > b {
font-weight: bold;
}
-#content table tr td:nth-of-type(6) b {
+#content tr td:nth-of-type(6) b {
font-weight: normal;
}
-#content table tr.blocked td:nth-of-type(6) b {
+#content tr.blocked td:nth-of-type(6) b {
background-color: rgba(192, 0, 0, 0.2);
}
-body.colorBlind #content table tr.blocked td:nth-of-type(6) b {
+body.colorBlind #content tr.blocked td:nth-of-type(6) b {
background-color: rgba(0, 19, 110, 0.2);
}
-#content table tr.allowed td:nth-of-type(6) b {
+#content tr.allowed td:nth-of-type(6) b {
background-color: rgba(0, 160, 0, 0.2);
}
-body.colorBlind #content table tr.allowed td:nth-of-type(6) b {
+body.colorBlind #content tr.allowed td:nth-of-type(6) b {
background-color: rgba(255, 194, 57, 0.2);
}
@@ -255,3 +262,150 @@ body[dir="rtl"] #popupContainer > div {
#popupContainer.hide > iframe {
display: none;
}
+
+#urlFilteringMenu {
+ background-color: rgba(0, 0, 0, 0.5);
+ border: 0;
+ bottom: 0;
+ left: 0;
+ margin: 0;
+ position: fixed;
+ right: 0;
+ top: 0;
+ z-index: 100;
+ }
+#urlFilteringMenu .dialog {
+ background-color: white;
+ border: 1px solid gray;
+ padding: 0.2em;
+ position: fixed;
+ }
+#urlFilteringMenu .dialog > div:first-child {
+ padding: 0.2em 0.2em 0.4em 0.2em;
+ }
+#urlFilteringMenu .dialog > div:first-child > * {
+ display: inline-block;
+ vertical-align: middle;
+ }
+#urlFilteringMenu .save {
+ background-color: #ffe;
+ border: 1px solid #ddc;
+ border-radius: 4px;
+ color: #888;
+ cursor: pointer;
+ font-size: 1.8em;
+ margin-right: 0.1em;
+ padding: 0.1em 0.5em;
+ visibility: hidden;
+ }
+body.dirty #urlFilteringMenu .save {
+ visibility: visible;
+ }
+#urlFilteringMenu .save:hover {
+ color: black;
+ }
+#urlFilteringMenu select {
+ font: inherit;
+ }
+#urlFilteringMenu .entries {
+ font-size: 13px;
+ max-height: 12em;
+ max-width: 70vw;
+ overflow-y: auto;
+ }
+#urlFilteringMenu .entries > div {
+ background-color: #e6e6e6;
+ border: 0;
+ line-height: 2em;
+ margin: 0;
+ margin-top: 1px;
+ overflow: hidden;
+ padding: 0;
+ white-space: nowrap;
+ width: 100%;
+ }
+#urlFilteringMenu .entries > div:first-child {
+ margin-top: 0;
+ }
+#urlFilteringMenu .entries > div:hover {
+ background-color: #f0f0f0;
+ }
+#urlFilteringMenu .entries > div > .action {
+ background-color: transparent;
+ border: 0;
+ border-right: 1px solid white;
+ cursor: pointer;
+ display: inline-block;
+ height: 100%;
+ width: 3.8em;
+ }
+#urlFilteringMenu .entries > div > .action.allow {
+ background-color: rgba(0, 160, 0, 0.3);
+ }
+body.colorBlind #urlFilteringMenu .entries > div > .action.allow {
+ background-color: rgba(255, 194, 57, 0.4);
+ }
+#urlFilteringMenu .entries > div > .action.noop {
+ background-color: rgba(108, 108, 108, 0.3);
+ }
+body.colorBlind #urlFilteringMenu .entries > div > .action.noop {
+ background-color: rgba(96, 96, 96, 0.4);
+ }
+#urlFilteringMenu .entries > div > .action.block {
+ background-color: rgba(192, 0, 0, 0.3);
+ }
+body.colorBlind #urlFilteringMenu .entries > div > .action.block {
+ background-color: rgba(0, 19, 110, 0.4);
+ }
+#urlFilteringMenu .entries > div > .action.allow.own {
+ background-color: rgba(0, 160, 0, 1);
+ }
+body.colorBlind #urlFilteringMenu .entries > div > .action.allow.own {
+ background-color: rgba(255, 194, 57, 1);
+ }
+#urlFilteringMenu .entries > div > .action.noop.own {
+ background-color: rgba(108, 108, 108, 1);
+ }
+#urlFilteringMenu .entries > div > .action.block.own {
+ background-color: rgba(192, 0, 0, 1);
+ }
+body.colorBlind #urlFilteringMenu .entries > div > .action.block.own {
+ background-color: rgba(0, 19, 110, 1);
+ }
+#urlFilteringMenu .entries > div > .action > span {
+ background-color: transparent;
+ border: 0;
+ display: inline-block;
+ height: 100%;
+ opacity: 0.2;
+ visibility: hidden;
+ width: 33.33%;
+ }
+#urlFilteringMenu .entries > div > .action > span:before {
+ content: '\00A0';
+ }
+#urlFilteringMenu .entries > div > .action:not(.own):hover > span {
+ opacity: 0.2;
+ visibility: visible;
+ }
+#urlFilteringMenu .entries > div > .action:not(.own):hover > span:hover {
+ opacity: 0.75;
+ }
+#urlFilteringMenu .entries > div > .action > .allow {
+ background-color: rgb(0, 160, 0);
+ }
+body.colorBlind #urlFilteringMenu .entries > div > .action > .allow {
+ background-color: rgb(255, 194, 57);
+ }
+#urlFilteringMenu .entries > div > .action > .noop {
+ background-color: rgb(108, 108, 108);
+ }
+#urlFilteringMenu .entries > div > .action > .block {
+ background-color: rgb(192, 0, 0);
+ }
+body.colorBlind #urlFilteringMenu .entries > div > .action > .block {
+ background-color: rgb(0, 19, 110);
+ }
+#urlFilteringMenu .entries > div > .url {
+ padding: 0 0.25em;
+ }
diff --git a/src/js/dyna-rules.js b/src/js/dyna-rules.js
index ce8dcec..0483061 100644
--- a/src/js/dyna-rules.js
+++ b/src/js/dyna-rules.js
@@ -41,7 +41,9 @@ var renderRules = function(details) {
var rules, rule, i;
// Switches always displayed first -- just like in uMatrix
+ // Merge url rules and switches: they just look the same
rules = details.hnSwitches.split(/\n+/).sort();
+
for ( i = 0; i < rules.length; i++ ) {
rule = rules[i];
liLeft = liTemplate.clone().text(rule);
@@ -120,7 +122,7 @@ function handleImportFilePicker() {
.replace(/\n/g, ' * noop\n');
}
var request = {
- 'what': 'setSessionFirewallRules',
+ 'what': 'setSessionRules',
'rules': rulesFromHTML('#diff .right li') + '\n' + result
};
messager.send(request, renderRules);
@@ -183,7 +185,7 @@ var rulesFromHTML = function(selector) {
var revertHandler = function() {
var request = {
- 'what': 'setSessionFirewallRules',
+ 'what': 'setSessionRules',
'rules': rulesFromHTML('#diff .left li')
};
messager.send(request, renderRules);
@@ -193,7 +195,7 @@ var revertHandler = function() {
var commitHandler = function() {
var request = {
- 'what': 'setPermanentFirewallRules',
+ 'what': 'setPermanentRules',
'rules': rulesFromHTML('#diff .right li')
};
messager.send(request, renderRules);
@@ -217,7 +219,7 @@ var editStopHandler = function() {
var parent = uDom(this).ancestors('#diff');
parent.toggleClass('edit', false);
var request = {
- 'what': 'setSessionFirewallRules',
+ 'what': 'setSessionRules',
'rules': uDom('#diff .right textarea').val()
};
messager.send(request, renderRules);
@@ -245,7 +247,7 @@ uDom.onLoad(function() {
uDom('#editStopButton').on('click', editStopHandler);
uDom('#editCancelButton').on('click', editCancelHandler);
- messager.send({ what: 'getFirewallRules' }, renderRules);
+ messager.send({ what: 'getRules' }, renderRules);
});
/******************************************************************************/
diff --git a/src/js/dynamic-net-filtering.js b/src/js/dynamic-net-filtering.js
index 16e1d68..b44fc21 100644
--- a/src/js/dynamic-net-filtering.js
+++ b/src/js/dynamic-net-filtering.js
@@ -440,19 +440,21 @@ Matrix.prototype.mustAbort = function() {
/******************************************************************************/
Matrix.prototype.toFilterString = function() {
+ if ( this.r === 0 ) {
+ return '';
+ }
if ( this.type === '' ) {
return '';
}
+ var body = this.z + ' ' + this.y + ' ' + this.type;
if ( this.r === 1 ) {
- return 'db:' + this.z + ' ' + this.y + ' ' + this.type + ' block';
+ return 'db:' + body + ' block';
}
if ( this.r === 2 ) {
- return 'da:' + this.z + ' ' + this.y + ' ' + this.type + ' allow';
+ return 'da:' + body + ' allow';
}
- if ( this.r === 3 ) {
- return 'dn:' + this.z + ' ' + this.y + ' ' + this.type + ' noop';
- }
- return '';
+ /* this.r === 3 */
+ return 'dn:' + body + ' noop';
};
/******************************************************************************/
@@ -529,6 +531,11 @@ Matrix.prototype.fromString = function(text, append) {
continue;
}
+ // URL net filtering rules
+ if ( line.indexOf('://') !== -1 ) {
+ continue;
+ }
+
// Valid rule syntax:
// srcHostname desHostname type state
@@ -542,6 +549,12 @@ Matrix.prototype.fromString = function(text, append) {
continue;
}
+ // Ignore special rules:
+ // hostname-based switch rules
+ if ( fields[0].slice(-1) === ':' ) {
+ continue;
+ }
+
srcHostname = punycode.toASCII(fields[0]);
desHostname = punycode.toASCII(fields[1]);
diff --git a/src/js/logger-ui.js b/src/js/logger-ui.js
index c9fd053..e3619d7 100644
--- a/src/js/logger-ui.js
+++ b/src/js/logger-ui.js
@@ -50,6 +50,7 @@ var noTabId = '';
var allTabIds = {};
var allTabIdsToken;
var hiddenTemplate = document.querySelector('#hiddenTemplate > span');
+var reRFC3986 = /^([^:\/?#]+:)?(\/\/[^\/?#]*)?([^?#]*)(\?[^#]*)?(#.*)?/;
var prettyRequestTypes = {
'main_frame': 'doc',
@@ -58,6 +59,13 @@ var prettyRequestTypes = {
'xmlhttprequest': 'xhr'
};
+var uglyRequestTypes = {
+ 'doc': 'main_frame',
+ 'css': 'stylesheet',
+ 'frame': 'sub_frame',
+ 'xhr': 'xmlhttprequest'
+};
+
var timeOptions = {
hour: '2-digit',
minute: '2-digit',
@@ -84,40 +92,65 @@ var classNameFromTabId = function(tabId) {
/******************************************************************************/
+var retextFromStaticFilteringResult = function(result) {
+ var retext = result.slice(3);
+ var pos = retext.indexOf('$');
+ if ( pos > 0 ) {
+ retext = retext.slice(0, pos);
+ }
+ if ( retext === '*' ) {
+ return '^.*$';
+ }
+ if ( retext.charAt(0) === '/' && retext.slice(-1) === '/' ) {
+ return retext.slice(1, -1);
+ }
+ return retext
+ .replace(/\./g, '\\.')
+ .replace(/\?/g, '\\?')
+ .replace('||', '')
+ .replace(/\^/g, '.')
+ .replace(/^\|/g, '^')
+ .replace(/\|$/g, '$')
+ .replace(/\*/g, '.*')
+ ;
+};
+
+/******************************************************************************/
+
+var retextFromURLFilteringResult = function(result) {
+ var beg = result.indexOf(' ');
+ var end = result.indexOf(' ', beg + 1);
+ var url = result.slice(beg + 1, end);
+ if ( url === '*' ) {
+ return '^.*$';
+ }
+ return '^' + url.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+};
+
+/******************************************************************************/
+
// Emphasize hostname in URL, as this is what matters in uMatrix's rules.
var nodeFromURL = function(url, filter) {
- if ( filter.charAt(0) !== 's' ) {
+ var filterType = filter.charAt(0);
+ if ( filterType !== 's' && filterType !== 'l' ) {
return document.createTextNode(url);
}
-
// make a regex out of the filter
- var reText = filter.slice(3);
- var pos = reText.indexOf('$');
- if ( pos > 0 ) {
- reText = reText.slice(0, pos);
+ var retext = '';
+ if ( filterType === 's' ) {
+ retext = retextFromStaticFilteringResult(filter);
+ } else if ( filterType === 'l' ) {
+ retext = retextFromURLFilteringResult(filter);
}
- if ( reText === '*' ) {
- reText = '\\*';
- } else if ( reText.charAt(0) === '/' && reText.slice(-1) === '/' ) {
- reText = reText.slice(1, -1);
- } else {
- reText = reText
- .replace(/\./g, '\\.')
- .replace(/\?/g, '\\?')
- .replace('||', '')
- .replace(/\^/g, '.')
- .replace(/^\|/g, '^')
- .replace(/\|$/g, '$')
- .replace(/\*/g, '.*')
- ;
- }
- var re = new RegExp(reText, 'gi');
+ if ( retext === '' ) {
+ return document.createTextNode(url);
+ }
+ var re = new RegExp(retext, 'gi');
var matches = re.exec(url);
if ( matches === null || matches[0].length === 0 ) {
return document.createTextNode(url);
}
-
var node = renderedURLTemplate.cloneNode(true);
node.childNodes[0].textContent = url.slice(0, matches.index);
node.childNodes[1].textContent = url.slice(matches.index, re.lastIndex);
@@ -153,6 +186,7 @@ var createRow = function(layout) {
var tr = trJunkyard.pop();
if ( tr ) {
tr.className = '';
+ tr.removeAttribute('data-context');
} else {
tr = document.createElement('tr');
}
@@ -212,6 +246,7 @@ var renderNetLogEntry = function(tr, entry) {
var filter = entry.d0;
var type = entry.d1;
var url = entry.d2;
+ var td;
tr.classList.add('canMtx');
@@ -221,19 +256,26 @@ var renderNetLogEntry = function(tr, entry) {
createGap(entry.tab, url);
}
+ // Root hostname
+ if ( entry.d3 ) {
+ tr.setAttribute('data-context', entry.d3);
+ }
+
// Cosmetic filter?
- if ( filter.charAt(0) === 'c' ) {
- tr.classList.add('cosmetic');
+ var filterCat = filter.slice(0, 3);
+ if ( filterCat.charAt(2) === ':' ) {
+ tr.classList.add(filterCat.slice(0, 2));
}
+ td = tr.cells[2];
if ( filter.charAt(1) === 'b' ) {
tr.classList.add('blocked');
- tr.cells[2].textContent = ' --';
+ td.textContent = '--';
} else if ( filter.charAt(1) === 'a' ) {
tr.classList.add('allowed');
- tr.cells[2].textContent = ' ++';
+ td.textContent = '++';
} else {
- tr.cells[2].textContent = '';
+ td.textContent = '';
}
var filterText = filter.slice(3);
@@ -241,8 +283,8 @@ var renderNetLogEntry = function(tr, entry) {
filterText = '@@' + filterText;
}
- tr.cells[3].textContent = filterText + '\t';
- tr.cells[4].textContent = (prettyRequestTypes[type] || type) + '\t';
+ tr.cells[3].textContent = filterText;
+ tr.cells[4].textContent = (prettyRequestTypes[type] || type);
tr.cells[5].appendChild(nodeFromURL(url, filter));
};
@@ -531,6 +573,236 @@ var onMaxEntriesChanged = function() {
};
/******************************************************************************/
+/******************************************************************************/
+
+var urlFilteringMenu = (function() {
+ var menu = document.querySelector('#urlFilteringMenu');
+ var menuDialog = menu.querySelector('.dialog');
+ var selectContext = menuDialog.querySelector('.context');
+ var selectType = menuDialog.querySelector('.type');
+ var menuEntries = menu.querySelector('.entries');
+ var menuURLs = [];
+
+ var removeAllChildren = function(node) {
+ while ( node.firstChild ) {
+ node.removeChild(node.firstChild);
+ }
+ };
+
+ var uglyTypeFromSelector = function() {
+ var prettyType = selectType.value;
+ return uglyRequestTypes[prettyType] || prettyType;
+ };
+
+ var onColorsReady = function(response) {
+ document.body.classList.toggle('dirty', response.dirty);
+ var colorEntries = response.colors;
+ var colorEntry, node;
+ for ( var url in colorEntries ) {
+ if ( colorEntries.hasOwnProperty(url) === false ) {
+ continue;
+ }
+ colorEntry = colorEntries[url];
+ node = menu.querySelector('.entries [data-url="' + url + '"]');
+ if ( node === null ) {
+ continue;
+ }
+ node.classList.toggle('allow', colorEntry.r === 2);
+ node.classList.toggle('noop', colorEntry.r === 3);
+ node.classList.toggle('block', colorEntry.r === 1);
+ node.classList.toggle('own', colorEntry.own);
+ }
+ };
+
+ var colorize = function() {
+ messager.send({
+ what: 'getURLFilteringData',
+ context: selectContext.value,
+ urls: menuURLs,
+ type: uglyTypeFromSelector()
+ }, onColorsReady);
+ };
+
+ var onClick = function(ev) {
+ var target = ev.target;
+
+ // click outside the url filtering menu
+ if ( target.id === 'urlFilteringMenu' ) {
+ toggleOff();
+ return;
+ }
+
+ ev.stopPropagation();
+
+ // Save url filtering rule(s)
+ if ( target.classList.contains('save') ) {
+ messager.send({
+ what: 'saveURLFilteringRules',
+ context: selectContext.value,
+ urls: menuURLs,
+ type: uglyTypeFromSelector()
+ }, colorize);
+ return;
+ }
+
+ // Remove url filtering rule
+ if ( target.classList.contains('action') ) {
+ messager.send({
+ what: 'setURLFilteringRule',
+ context: selectContext.value,
+ url: target.getAttribute('data-url'),
+ type: uglyTypeFromSelector(),
+ action: 0
+ }, colorize);
+ return;
+ }
+
+ // add "allow" url filtering rule
+ if ( target.classList.contains('allow') ) {
+ messager.send({
+ what: 'setURLFilteringRule',
+ context: selectContext.value,
+ url: target.parentNode.getAttribute('data-url'),
+ type: uglyTypeFromSelector(),
+ action: 2
+ }, colorize);
+ return;
+ }
+
+ // add "block" url filtering rule
+ if ( target.classList.contains('noop') ) {
+ messager.send({
+ what: 'setURLFilteringRule',
+ context: selectContext.value,
+ url: target.parentNode.getAttribute('data-url'),
+ type: uglyTypeFromSelector(),
+ action: 3
+ }, colorize);
+ return;
+ }
+
+ // add "block" url filtering rule
+ if ( target.classList.contains('block') ) {
+ messager.send({
+ what: 'setURLFilteringRule',
+ context: selectContext.value,
+ url: target.parentNode.getAttribute('data-url'),
+ type: uglyTypeFromSelector(),
+ action: 1
+ }, colorize);
+ return;
+ }
+ };
+
+ var toggleOn = function(ev) {
+ var td = ev.target;
+ var tr = td.parentElement;
+ var cells = tr.cells;
+
+ var context = tr.getAttribute('data-context');
+ if ( !context ) {
+ return;
+ }
+
+ var type = cells[4].textContent.trim();
+ if ( !type ) {
+ return;
+ }
+
+ var pos, option;
+
+ // Fill context selector
+ removeAllChildren(selectContext);
+ for (;;) {
+ option = document.createElement('option');
+ option.textContent = context;
+ option.setAttribute('value', context);
+ pos = context.indexOf('.');
+ selectContext.appendChild(option);
+ if ( pos === -1 ) {
+ break;
+ }
+ context = context.slice(pos + 1);
+ }
+ option = document.createElement('option');
+ option.textContent = '*';
+ option.setAttribute('value', '*');
+ selectContext.appendChild(option);
+
+ // Fill type selector
+ selectType.options[0].textContent = type;
+ selectType.options[0].setAttribute('value', type);
+ selectType.selectedIndex = 0;
+
+ // Extract data needed to build URL filtering menu
+ var candidateURL = cells[5].textContent;
+ var matches = reRFC3986.exec(candidateURL);
+ if ( matches === null || !matches[1] || !matches[2] ) {
+ return;
+ }
+
+ // Shortest URL which for a valid URL filtering rule
+ var candidateRootURL = matches[1] + matches[2];
+ menuURLs.push(candidateRootURL);
+ var candidatePath = matches[3] || '';
+ pos = candidatePath.charAt(0) === '/' ? 1 : 0;
+ while ( pos < candidatePath.length ) {
+ pos = candidatePath.indexOf('/', pos + 1);
+ if ( pos === -1 ) {
+ pos = candidatePath.length;
+ }
+ menuURLs.push(candidateRootURL + candidatePath.slice(0, pos));
+ }
+ var candidateQuery = matches[4] || '';
+ if ( candidateQuery !== '') {
+ menuURLs.push(candidateRootURL + candidatePath + candidateQuery);
+ }
+
+ // Fill menu
+ var menuEntryTemplate = document.querySelector('#templates .urlFilteringMenuEntry');
+
+ // Adding URL filtering rules
+ var i = menuURLs.length;
+ var url, menuEntry;
+ while ( i-- ) {
+ url = menuURLs[i];
+ menuEntry = menuEntryTemplate.cloneNode(true);
+ menuEntry.children[0].setAttribute('data-url', url);
+ menuEntry.children[1].textContent = url;
+ menuEntries.appendChild(menuEntry);
+ }
+
+ colorize();
+
+ var rect = td.getBoundingClientRect();
+ menuDialog.style.setProperty('left', rect.left + 'px');
+ menuDialog.style.setProperty('top', rect.bottom + 'px');
+ document.body.appendChild(menu);
+
+ menu.addEventListener('click', onClick, true);
+ selectContext.addEventListener('change', colorize);
+ selectType.addEventListener('change', colorize);
+ };
+
+ var toggleOff = function() {
+ if ( menu.parentNode === null ) {
+ return;
+ }
+ removeAllChildren(menuEntries);
+ selectContext.removeEventListener('change', colorize);
+ selectType.removeEventListener('change', colorize);
+ menu.removeEventListener('click', onClick, true);
+ menu.parentNode.removeChild(menu);
+ menuURLs = [];
+ };
+
+ return {
+ toggleOn: toggleOn
+ };
+})();
+
+/******************************************************************************/
+/******************************************************************************/
var rowFilterer = (function() {
var filters = [];
@@ -823,6 +1095,7 @@ uDom.onLoad(function() {
uDom('#clear').on('click', clearBuffer);
uDom('#maxEntries').on('change', onMaxEntriesChanged);
uDom('#content table').on('click', 'tr.canMtx > td:nth-of-type(2)', popupManager.toggleOn);
+ uDom('#content').on('click', 'tr.cat_net > td:nth-of-type(3)', urlFilteringMenu.toggleOn);
});
/******************************************************************************/
diff --git a/src/js/logger.js b/src/js/logger.js
index 2da5757..91bc04f 100644
--- a/src/js/logger.js
+++ b/src/js/logger.js
@@ -161,6 +161,7 @@ var janitor = function() {
logBuffer !== null &&
logBuffer.lastReadTime < (Date.now() - logBufferObsoleteAfter)
) {
+ api.writeOne = writeOneNoop;
logBuffer = logBuffer.dispose();
}
if ( logBuffer !== null ) {
@@ -170,16 +171,18 @@ var janitor = function() {
/******************************************************************************/
+var writeOneNoop = function() {
+};
+
var writeOne = function() {
- if ( logBuffer !== null ) {
- logBuffer.writeOne(arguments);
- }
+ logBuffer.writeOne(arguments);
};
/******************************************************************************/
var readAll = function() {
if ( logBuffer === null ) {
+ api.writeOne = writeOne;
logBuffer = new LogBuffer();
vAPI.setTimeout(janitor, logBufferObsoleteAfter);
}
@@ -188,18 +191,20 @@ var readAll = function() {
/******************************************************************************/
-var isObserved = function() {
+var isEnabled = function() {
return logBuffer !== null;
};
/******************************************************************************/
-return {
- writeOne: writeOne,
+var api = {
+ writeOne: writeOneNoop,
readAll: readAll,
- isObserved: isObserved
+ isEnabled: isEnabled
};
+return api;
+
/******************************************************************************/
/******************************************************************************/
diff --git a/src/js/messaging.js b/src/js/messaging.js
index 56ebe6b..a39d800 100644
--- a/src/js/messaging.js
+++ b/src/js/messaging.js
@@ -183,30 +183,30 @@ var getHostnameDict = function(hostnameToCountMap) {
var getFirewallRules = function(srcHostname, desHostnames) {
var r = {};
- var dFiltering = µb.sessionFirewall;
- r['/ * *'] = dFiltering.evaluateCellZY('*', '*', '*').toFilterString();
- r['/ * image'] = dFiltering.evaluateCellZY('*', '*', 'image').toFilterString();
- r['/ * 3p'] = dFiltering.evaluateCellZY('*', '*', '3p').toFilterString();
- r['/ * inline-script'] = dFiltering.evaluateCellZY('*', '*', 'inline-script').toFilterString();
- r['/ * 1p-script'] = dFiltering.evaluateCellZY('*', '*', '1p-script').toFilterString();
- r['/ * 3p-script'] = dFiltering.evaluateCellZY('*', '*', '3p-script').toFilterString();
- r['/ * 3p-frame'] = dFiltering.evaluateCellZY('*', '*', '3p-frame').toFilterString();
+ var df = µb.sessionFirewall;
+ r['/ * *'] = df.evaluateCellZY('*', '*', '*').toFilterString();
+ r['/ * image'] = df.evaluateCellZY('*', '*', 'image').toFilterString();
+ r['/ * 3p'] = df.evaluateCellZY('*', '*', '3p').toFilterString();
+ r['/ * inline-script'] = df.evaluateCellZY('*', '*', 'inline-script').toFilterString();
+ r['/ * 1p-script'] = df.evaluateCellZY('*', '*', '1p-script').toFilterString();
+ r['/ * 3p-script'] = df.evaluateCellZY('*', '*', '3p-script').toFilterString();
+ r['/ * 3p-frame'] = df.evaluateCellZY('*', '*', '3p-frame').toFilterString();
if ( typeof srcHostname !== 'string' ) {
return r;
}
- r['. * *'] = dFiltering.evaluateCellZY(srcHostname, '*', '*').toFilterString();
- r['. * image'] = dFiltering.evaluateCellZY(srcHostname, '*', 'image').toFilterString();
- r['. * 3p'] = dFiltering.evaluateCellZY(srcHostname, '*', '3p').toFilterString();
- r['. * inline-script'] = dFiltering.evaluateCellZY(srcHostname, '*', 'inline-script').toFilterString();
- r['. * 1p-script'] = dFiltering.evaluateCellZY(srcHostname, '*', '1p-script').toFilterString();
- r['. * 3p-script'] = dFiltering.evaluateCellZY(srcHostname, '*', '3p-script').toFilterString();
- r['. * 3p-frame'] = dFiltering.evaluateCellZY(srcHostname, '*', '3p-frame').toFilterString();
+ r['. * *'] = df.evaluateCellZY(srcHostname, '*', '*').toFilterString();
+ r['. * image'] = df.evaluateCellZY(srcHostname, '*', 'image').toFilterString();
+ r['. * 3p'] = df.evaluateCellZY(srcHostname, '*', '3p').toFilterString();
+ r['. * inline-script'] = df.evaluateCellZY(srcHostname, '*', 'inline-script').toFilterString();
+ r['. * 1p-script'] = df.evaluateCellZY(srcHostname, '*', '1p-script').toFilterString();
+ r['. * 3p-script'] = df.evaluateCellZY(srcHostname, '*', '3p-script').toFilterString();
+ r['. * 3p-frame'] = df.evaluateCellZY(srcHostname, '*', '3p-frame').toFilterString();
for ( var desHostname in desHostnames ) {
if ( desHostnames.hasOwnProperty(desHostname) ) {
- r['/ ' + desHostname + ' *'] = dFiltering.evaluateCellZY('*', desHostname, '*').toFilterString();
- r['. ' + desHostname + ' *'] = dFiltering.evaluateCellZY(srcHostname, desHostname, '*').toFilterString();
+ r['/ ' + desHostname + ' *'] = df.evaluateCellZY('*', desHostname, '*').toFilterString();
+ r['. ' + desHostname + ' *'] = df.evaluateCellZY(srcHostname, desHostname, '*').toFilterString();
}
}
return r;
@@ -853,18 +853,19 @@ var µb = µBlock;
var getRules = function() {
return {
- permanentRules: µb.permanentFirewall.toString(),
- sessionRules: µb.sessionFirewall.toString(),
+ permanentRules: µb.permanentFirewall.toString() + '\n' + µb.permanentURLFiltering.toString(),
+ sessionRules: µb.sessionFirewall.toString() + '\n' + µb.sessionURLFiltering.toString(),
hnSwitches: µb.hnSwitches.toString()
};
};
-// Untangle rules and switches.
+// Untangle firewall rules, url rules and switches.
var untangle = function(s) {
var textEnd = s.length;
var lineBeg = 0, lineEnd;
var line;
- var rules = [];
+ var firewallRules = [];
+ var urlRules = [];
var switches = [];
while ( lineBeg < textEnd ) {
@@ -878,16 +879,18 @@ var untangle = function(s) {
line = s.slice(lineBeg, lineEnd).trim();
lineBeg = lineEnd + 1;
- // Switches always contain a ':'
- if ( line.indexOf(':') === -1 ) {
- rules.push(line);
+ if ( line.indexOf('://') !== -1 ) {
+ urlRules.push(line);
+ } else if ( line.indexOf(':') === -1 ) {
+ firewallRules.push(line);
} else {
switches.push(line);
}
}
return {
- rules: rules.join('\n'),
+ firewallRules: firewallRules.join('\n'),
+ urlRules: urlRules.join('\n'),
switches: switches.join('\n')
};
};
@@ -906,24 +909,27 @@ var onMessage = function(request, sender, callback) {
var response;
switch ( request.what ) {
- case 'getFirewallRules':
+ case 'getRules':
response = getRules();
break;
- case 'setSessionFirewallRules':
+ case 'setSessionRules':
// https://github.com/chrisaljoudi/uBlock/issues/772
µb.cosmeticFilteringEngine.removeFromSelectorCache('*');
r = untangle(request.rules);
- µb.sessionFirewall.fromString(r.rules);
+ µb.sessionFirewall.fromString(r.firewallRules);
+ µb.sessionURLFiltering.fromString(r.urlRules);
µb.hnSwitches.fromString(r.switches);
µb.saveHostnameSwitches();
response = getRules();
break;
- case 'setPermanentFirewallRules':
+ case 'setPermanentRules':
r = untangle(request.rules);
- µb.permanentFirewall.fromString(r.rules);
+ µb.permanentFirewall.fromString(r.firewallRules);
µb.savePermanentFirewallRules();
+ µb.permanentURLFiltering.fromString(r.urlRules);
+ µb.savePermanentURLFilteringRules();
µb.hnSwitches.fromString(r.switches);
µb.saveHostnameSwitches();
response = getRules();
@@ -1031,6 +1037,7 @@ var backupUserData = function(callback) {
filterLists: {},
netWhitelist: µb.stringFromWhitelist(µb.netWhitelist),
dynamicFilteringString: µb.permanentFirewall.toString(),
+ urlFilteringString: µb.permanentURLFiltering.toString(),
hostnameSwitchesString: µb.hnSwitches.toString(),
userFilters: ''
};
@@ -1067,7 +1074,7 @@ var backupUserData = function(callback) {
var restoreUserData = function(request) {
var userData = request.userData;
- var countdown = 7;
+ var countdown = 8;
var onCountdown = function() {
countdown -= 1;
if ( countdown === 0 ) {
@@ -1088,6 +1095,7 @@ var restoreUserData = function(request) {
var s = userData.dynamicFilteringString || userData.userSettings.dynamicFilteringString || '';
µb.keyvalSetOne('dynamicFilteringString', s, onCountdown);
+ µb.keyvalSetOne('urlFilteringString', userData.urlFilteringString || '', onCountdown);
µb.keyvalSetOne('hostnameSwitchesString', userData.hostnameSwitchesString || '', onCountdown);
µb.assets.put('assets/user/filters.txt', userData.userFilters, onCountdown);
vAPI.storage.set({
@@ -1173,6 +1181,66 @@ var µb = µBlock;
/******************************************************************************/
+var getURLFilteringData = function(details) {
+ var colors = {};
+ var response = {
+ dirty: false,
+ colors: colors
+ };
+ var suf = µb.sessionURLFiltering;
+ var puf = µb.permanentURLFiltering;
+ var urls = details.urls,
+ context = details.context,
+ type = details.type;
+ var url, colorEntry;
+ var i = urls.length;
+ while ( i-- ) {
+ url = urls[i];
+ colorEntry = colors[url] = { r: 0, own: false };
+ if ( suf.evaluateZ(context, url, type).r !== 0 ) {
+ colorEntry.r = suf.r;
+ colorEntry.own = suf.context === context && suf.url === url && suf.type === type;
+ }
+ if ( response.dirty ) {
+ continue;
+ }
+ puf.evaluateZ(context, url, type);
+ response.dirty = colorEntry.own !== (puf.context === context && puf.url === url && puf.type === type);
+ }
+ return response;
+};
+
+/******************************************************************************/
+
+var saveTemporaryURLFilteringRules = function(details) {
+ var changed = false;
+ var suf = µb.sessionURLFiltering;
+ var puf = µb.permanentURLFiltering;
+ var urls = details.urls,
+ context = details.context,
+ type = details.type;
+ var url, sOwn, pOwn;
+ var i = urls.length;
+ while ( i-- ) {
+ url = urls[i];
+ suf.evaluateZ(context, url, type);
+ sOwn = suf.context === context && suf.url === url && suf.type === type;
+ puf.evaluateZ(context, url, type);
+ pOwn = puf.context === context && puf.url === url && puf.type === type;
+ if ( sOwn && !pOwn ) {
+ puf.setRule(context, url, type, suf.r);
+ changed = true;
+ }
+ if ( !sOwn && pOwn ) {
+ puf.removeRule(context, url, type);
+ changed = true;
+ }
+ }
+ return changed;
+};
+
+/******************************************************************************/
+
var onMessage = function(request, sender, callback) {
// Async
switch ( request.what ) {
@@ -1207,6 +1275,20 @@ var onMessage = function(request, sender, callback) {
};
break;
+ case 'saveURLFilteringRules':
+ if ( saveTemporaryURLFilteringRules(request) ) {
+ µb.savePermanentURLFilteringRules();
+ }
+ break;
+
+ case 'setURLFilteringRule':
+ µb.toggleURLFilteringRule(request);
+ break;
+
+ case 'getURLFilteringData':
+ response = getURLFilteringData(request);
+ break;
+
default:
return vAPI.messaging.UNHANDLED;
}
diff --git a/src/js/pagestore.js b/src/js/pagestore.js
index 690f3da..0d19baa 100644
--- a/src/js/pagestore.js
+++ b/src/js/pagestore.js
@@ -1,7 +1,7 @@
/*******************************************************************************
- µBlock - a browser extension to block requests.
- Copyright (C) 2014 Raymond Hill
+ uBlock - a browser extension to block requests.
+ Copyright (C) 2014-2015 Raymond Hill
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -498,26 +498,21 @@ PageStore.prototype.filterRequest = function(context) {
return entry.result;
}
- var result = '';
+ µb.sessionURLFiltering.evaluateZ(context.rootHostname, context.requestURL, context.requestType);
+ var result = µb.sessionURLFiltering.toFilterString();
// Given that:
// - Dynamic filtering override static filtering
// - Evaluating dynamic filtering is much faster than static filtering
// We evaluate dynamic filtering first, and hopefully we can skip
// evaluation of static filtering.
- if ( µb.userSettings.advancedUserEnabled ) {
- var df = µb.sessionFirewall.evaluateCellZY(
- context.rootHostname,
- context.requestHostname,
- context.requestType
- );
- if ( df.mustBlockOrAllow() ) {
- result = df.toFilterString();
- }
+ if ( result === '' && µb.userSettings.advancedUserEnabled ) {
+ µb.sessionFirewall.evaluateCellZY( context.rootHostname, context.requestHostname, context.requestType);
+ result = µb.sessionFirewall.toFilterString();
}
// Static filtering never override dynamic filtering
- if ( result === '' ) {
+ if ( result === '' || result.charAt(1) === 'n' ) {
result = µb.staticNetFilteringEngine.matchString(context);
}
@@ -541,26 +536,21 @@ PageStore.prototype.filterRequestNoCache = function(context) {
return '';
}
- var result = '';
+ µb.sessionURLFiltering.evaluateZ(context.rootHostname, context.requestURL, context.requestType);
+ var result = µb.sessionURLFiltering.toFilterString();
// Given that:
// - Dynamic filtering override static filtering
// - Evaluating dynamic filtering is much faster than static filtering
// We evaluate dynamic filtering first, and hopefully we can skip
// evaluation of static filtering.
- if ( µb.userSettings.advancedUserEnabled ) {
- var df = µb.sessionFirewall.evaluateCellZY(
- context.rootHostname,
- context.requestHostname,
- context.requestType
- );
- if ( df.mustBlockOrAllow() ) {
- result = df.toFilterString();
- }
+ if ( result === '' && µb.userSettings.advancedUserEnabled ) {
+ µb.sessionFirewall.evaluateCellZY(context.rootHostname, context.requestHostname, context.requestType);
+ result = µb.sessionFirewall.toFilterString();
}
// Static filtering never override dynamic filtering
- if ( result === '' ) {
+ if ( result === '' || result.charAt(1) === 'n' ) {
result = µb.staticNetFilteringEngine.matchString(context);
}
diff --git a/src/js/start.js b/src/js/start.js
index 911f7e3..913621e 100644
--- a/src/js/start.js
+++ b/src/js/start.js
@@ -1,6 +1,6 @@
/*******************************************************************************
- µBlock - a browser extension to block requests.
+ uBlock - a browser extension to block requests.
Copyright (C) 2014-2015 Raymond Hill
This program is free software: you can redistribute it and/or modify
@@ -142,11 +142,12 @@ var onUserSettingsReady = function(fetched) {
// https://github.com/chrisaljoudi/uBlock/issues/540
// Disabling local mirroring for the time being
userSettings.experimentalEnabled = false;
- µb.mirrors.toggle(false /* userSettings.experimentalEnabled */);
µb.contextMenu.toggle(userSettings.contextMenuEnabled);
µb.permanentFirewall.fromString(fetched.dynamicFilteringString);
µb.sessionFirewall.assign(µb.permanentFirewall);
+ µb.permanentURLFiltering.fromString(fetched.urlFilteringString);
+ µb.sessionURLFiltering.assign(µb.permanentURLFiltering);
µb.hnSwitches.fromString(fetched.hostnameSwitchesString);
// Remove obsolete setting
@@ -226,6 +227,7 @@ return function() {
var fetchableProps = {
'compiledMagic': '',
'dynamicFilteringString': '',
+ 'urlFilteringString': '',
'hostnameSwitchesString': '',
'lastRestoreFile': '',
'lastRestoreTime': 0,
diff --git a/src/js/storage.js b/src/js/storage.js
index 3823b22..f8d9407 100644
--- a/src/js/storage.js
+++ b/src/js/storage.js
@@ -1,6 +1,6 @@
/*******************************************************************************
- µBlock - a browser extension to block requests.
+ uBlock - a browser extension to block requests.
Copyright (C) 2014-2015 Raymond Hill
This program is free software: you can redistribute it and/or modify
@@ -83,6 +83,12 @@
/******************************************************************************/
+µBlock.savePermanentURLFilteringRules = function() {
+ this.keyvalSetOne('urlFilteringString', this.permanentURLFiltering.toString());
+};
+
+/******************************************************************************/
+
µBlock.saveHostnameSwitches = function() {
this.keyvalSetOne('hostnameSwitchesString', this.hnSwitches.toString());
};
diff --git a/src/js/tab.js b/src/js/tab.js
index 7650b3d..05e7052 100644
--- a/src/js/tab.js
+++ b/src/js/tab.js
@@ -482,7 +482,8 @@ vAPI.tabs.onPopup = function(details) {
'net',
result,
'popup',
- targetURL
+ targetURL,
+ openerHostname
);
// Not blocked
diff --git a/src/js/traffic.js b/src/js/traffic.js
index 1c98f76..700ae60 100644
--- a/src/js/traffic.js
+++ b/src/js/traffic.js
@@ -92,7 +92,7 @@ var onBeforeRequest = function(details) {
// Possible outcomes: blocked, allowed-passthru, allowed-mirror
pageStore.logRequest(requestContext, result);
- µb.logger.writeOne(tabId, 'net', result, requestType, requestURL);
+ µb.logger.writeOne(tabId, 'net', result, requestType, requestURL, requestContext.rootHostname);
// Not blocked
if ( µb.isAllowResult(result) ) {
@@ -187,7 +187,7 @@ var onBeforeRootFrameRequest = function(details) {
if ( pageStore ) {
pageStore.logRequest(context, result);
}
- µb.logger.writeOne(tabId, 'net', result, 'main_frame', requestURL);
+ µb.logger.writeOne(tabId, 'net', result, 'main_frame', requestURL, context.rootHostname);
// Not blocked
if ( µb.isAllowResult(result) ) {
@@ -279,7 +279,7 @@ var onBeforeBehindTheSceneRequest = function(details) {
}
pageStore.logRequest(context, result);
- µb.logger.writeOne(vAPI.noTabId, 'net', result, details.type, details.url);
+ µb.logger.writeOne(vAPI.noTabId, 'net', result, details.type, details.url, context.rootHostname);
// Not blocked
if ( µb.isAllowResult(result) ) {
@@ -328,7 +328,7 @@ var onHeadersReceived = function(details) {
var result = pageStore.filterRequestNoCache(context);
pageStore.logRequest(context, result);
- µb.logger.writeOne(tabId, 'net', result, 'inline-script', details.url);
+ µb.logger.writeOne(tabId, 'net', result, 'inline-script', details.url, context.rootHostname);
// Don't block
if ( µb.isAllowResult(result) ) {
@@ -378,7 +378,7 @@ var onRootFrameHeadersReceived = function(details) {
var result = pageStore.filterRequestNoCache(context);
pageStore.logRequest(context, result);
- µb.logger.writeOne(tabId, 'net', result, 'inline-script', details.url);
+ µb.logger.writeOne(tabId, 'net', result, 'inline-script', details.url, context.rootHostname);
// Don't block
if ( µb.isAllowResult(result) ) {
diff --git a/src/js/ublock.js b/src/js/ublock.js
index c8a4f31..9801572 100644
--- a/src/js/ublock.js
+++ b/src/js/ublock.js
@@ -254,8 +254,8 @@ var matchWhitelistDirective = function(url, hostname, directive) {
// Pre-change
switch ( name ) {
- default:
- break;
+ default:
+ break;
}
// Change
@@ -263,23 +263,18 @@ var matchWhitelistDirective = function(url, hostname, directive) {
// Post-change
switch ( name ) {
- case 'collapseBlocked':
- if ( value === false ) {
- this.cosmeticFilteringEngine.removeFromSelectorCache('*', 'net');
- }
- break;
- case 'contextMenuEnabled':
- this.contextMenu.toggle(value);
- break;
- case 'experimentalEnabled':
- if ( typeof this.mirrors === 'object' ) {
- // https://github.com/chrisaljoudi/uBlock/issues/540
- // Disabling local mirroring for the time being
- this.mirrors.toggle(false /* value */);
- }
- break;
- default:
- break;
+ case 'collapseBlocked':
+ if ( value === false ) {
+ this.cosmeticFilteringEngine.removeFromSelectorCache('*', 'net');
+ }
+ break;
+ case 'contextMenuEnabled':
+ this.contextMenu.toggle(value);
+ break;
+ case 'experimentalEnabled':
+ break;
+ default:
+ break;
}
this.saveUserSettings();
@@ -317,6 +312,23 @@ var matchWhitelistDirective = function(url, hostname, directive) {
/******************************************************************************/
+µBlock.toggleURLFilteringRule = function(details) {
+ var changed = this.sessionURLFiltering.setRule(
+ details.context,
+ details.url,
+ details.type,
+ details.action
+ );
+
+ if ( !changed ) {
+ return;
+ }
+
+ this.cosmeticFilteringEngine.removeFromSelectorCache(details.context, 'net');
+};
+
+/******************************************************************************/
+
µBlock.isBlockResult = function(result) {
return typeof result === 'string' && result.charAt(1) === 'b';
};
diff --git a/src/js/url-net-filtering.js b/src/js/url-net-filtering.js
new file mode 100644
index 0000000..fb8be64
--- /dev/null
+++ b/src/js/url-net-filtering.js
@@ -0,0 +1,391 @@
+/*******************************************************************************
+
+ uBlock - a browser extension to black/white list requests.
+ Copyright (C) 2015 Raymond Hill
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see {http://www.gnu.org/licenses/}.
+
+ Home: https://github.com/gorhill/uBlock
+*/
+
+/* global µBlock */
+
+/******************************************************************************/
+
+// The purpose of log filtering is to create ad hoc filtering rules, to
+// diagnose and assist in the creation of custom filters.
+
+µBlock.URLNetFiltering = (function() {
+
+'use strict';
+
+/*******************************************************************************
+
+buckets: map of [origin + urlkey]
+ bucket: array of rule entry, sorted from shorter to longer url
+
+rule entry: { url, action }
+
+
+*******************************************************************************/
+
+/******************************************************************************/
+
+var actionToNameMap = {
+ 1: 'block',
+ 2: 'allow',
+ 3: 'noop'
+};
+
+var nameToActionMap = {
+ 'block': 1,
+ 'allow': 2,
+ 'noop': 3
+};
+
+/******************************************************************************/
+
+var RuleEntry = function(url, action) {
+ this.url = url;
+ this.action = action;
+};
+
+/******************************************************************************/
+
+var indexOfURL = function(urls, url) {
+ // TODO: binary search -- maybe, depends on common use cases
+ var urlLen = url.length;
+ var entry;
+ // urls must be ordered by increasing length.
+ for ( var i = 0; i< urls.length; i++ ) {
+ entry = urls[i];
+ if ( entry.url.length > urlLen ) {
+ break;
+ }
+ if ( entry.url === url ) {
+ return i;
+ }
+ }
+ return -1;
+};
+
+/******************************************************************************/
+
+var indexOfMatch = function(urls, url) {
+ // TODO: binary search -- maybe, depends on common use cases
+ var urlLen = url.length;
+ var i = urls.length;
+ var entry;
+ while ( i-- ) {
+ entry = urls[i];
+ if ( entry.url.length > urlLen ) {
+ continue;
+ }
+ if ( url.lastIndexOf(entry.url, 0) === 0 ) {
+ return i;
+ }
+ }
+ return -1;
+};
+
+/******************************************************************************/
+
+var indexFromLength = function(urls, len) {
+ // TODO: binary search -- maybe, depends on common use cases
+ // urls must be ordered by increasing length.
+ for ( var i = 0; i< urls.length; i++ ) {
+ if ( urls[i].url.length > len ) {
+ return i;
+ }
+ }
+ return -1;
+};
+
+/******************************************************************************/
+
+var addRuleEntry = function(urls, url, action) {
+ var entry = new RuleEntry(url, action);
+ var i = indexFromLength(urls, url.length);
+ if ( i === -1 ) {
+ urls.push(entry);
+ } else {
+ urls.splice(i, 0, entry);
+ }
+};
+
+/******************************************************************************/
+
+var urlKeyFromURL = function(url) {
+ var match = reURLKey.exec(url);
+ return match !== null ? match[0] : '';
+};
+
+var reURLKey = /^[a-z]+:\/\/[^\/?#]+/;
+
+/******************************************************************************/
+
+var URLNetFiltering = function() {
+ this.reset();
+};
+
+/******************************************************************************/
+
+// rules:
+// hostname + urlkey => urls
+// urls = collection of urls to match
+
+URLNetFiltering.prototype.reset = function() {
+ this.rules = Object.create(null);
+ // registers, filled with result of last evaluation
+ this.context = '';
+ this.url = '';
+ this.type = '';
+ this.r = 0;
+};
+
+/******************************************************************************/
+
+URLNetFiltering.prototype.assign = function(other) {
+ var thisRules = this.rules;
+ var otherRules = other.rules;
+ var k;
+
+ // Remove rules not in other
+ for ( k in thisRules ) {
+ if ( otherRules[k] === undefined ) {
+ delete thisRules[k];
+ }
+ }
+
+ // Add/change rules in other
+ for ( k in otherRules ) {
+ thisRules[k] = otherRules[k].slice();
+ }
+};
+
+/******************************************************************************/
+
+URLNetFiltering.prototype.setRule = function(srcHostname, url, type, action) {
+ if ( action === 0 ) {
+ return this.removeRule(srcHostname, url, type);
+ }
+
+ var urlKey = urlKeyFromURL(url);
+ if ( urlKey === '' ) {
+ return false;
+ }
+
+ var bucketKey = srcHostname + ' ' + urlKey + ' ' + type;
+ var urls = this.rules[bucketKey];
+ if ( urls === undefined ) {
+ urls = this.rules[bucketKey] = [];
+ }
+
+ var entry;
+ var i = indexOfURL(urls, url);
+ if ( i !== -1 ) {
+ entry = urls[i];
+ if ( entry.action === action ) {
+ return false;
+ }
+ entry.action = action;
+ return true;
+ }
+
+ addRuleEntry(urls, url, action);
+ return true;
+};
+
+/******************************************************************************/
+
+URLNetFiltering.prototype.removeRule = function(srcHostname, url, type) {
+ var urlKey = urlKeyFromURL(url);
+ if ( urlKey === '' ) {
+ return false;
+ }
+
+ var bucketKey = srcHostname + ' ' + urlKey + ' ' + type;
+ var urls = this.rules[bucketKey];
+ if ( urls === undefined ) {
+ return false;
+ }
+
+ var i = indexOfURL(urls, url);
+ if ( i === -1 ) {
+ return false;
+ }
+
+ urls.splice(i, 1);
+ if ( urls.length === 0 ) {
+ delete this.rules[bucketKey];
+ }
+
+ return true;
+};
+
+/******************************************************************************/
+
+URLNetFiltering.prototype.evaluateZ = function(context, target, type) {
+ var urlKey = urlKeyFromURL(target);
+ if ( urlKey === '' ) {
+ this.r = 0;
+ return this;
+ }
+
+ var urls, pos, i, entry, prefixKey;
+
+ for (;;) {
+ this.context = context;
+ prefixKey = context + ' ' + urlKey;
+ if ( urls = this.rules[prefixKey + ' ' + type] ) {
+ i = indexOfMatch(urls, target);
+ if ( i !== -1 ) {
+ entry = urls[i];
+ this.url = entry.url;
+ this.type = type;
+ this.r = entry.action;
+ return this;
+ }
+ }
+ if ( urls = this.rules[prefixKey + ' *'] ) {
+ i = indexOfMatch(urls, target);
+ if ( i !== -1 ) {
+ entry = urls[i];
+ this.url = entry.url;
+ this.type = '*';
+ this.r = entry.action;
+ return this;
+ }
+ }
+ if ( context === '*' ) {
+ break;
+ }
+ pos = context.indexOf('.');
+ context = pos !== -1 ? context.slice(pos + 1) : '*';
+ }
+
+ this.r = 0;
+ return this;
+};
+
+/******************************************************************************/
+
+URLNetFiltering.prototype.mustBlockOrAllow = function() {
+ return this.r === 1 || this.r === 2;
+};
+
+/******************************************************************************/
+
+URLNetFiltering.prototype.toFilterString = function() {
+ if ( this.r === 0 ) {
+ return '';
+ }
+ var body = this.context + ' ' + this.url + ' ' + this.type;
+ if ( this.r === 1 ) {
+ return 'lb:' + body + ' block';
+ }
+ if ( this.r === 2 ) {
+ return 'la:' + body + ' allow';
+ }
+ /* this.r === 3 */
+ return 'ln:' + body + ' noop';
+};
+
+/******************************************************************************/
+
+// "url-filtering:" hostname url action
+
+URLNetFiltering.prototype.toString = function() {
+ var out = [];
+ var pos, hn, type, urls, i, entry;
+ for ( var bucketKey in this.rules ) {
+ pos = bucketKey.indexOf(' ');
+ hn = bucketKey.slice(0, pos);
+ pos = bucketKey.lastIndexOf(' ');
+ type = bucketKey.slice(pos + 1);
+ urls = this.rules[bucketKey];
+ for ( i = 0; i < urls.length; i++ ) {
+ entry = urls[i];
+ out.push(
+ hn + ' ' +
+ entry.url + ' ' +
+ type + ' ' +
+ actionToNameMap[entry.action]
+ );
+ }
+ }
+ return out.sort().join('\n');
+};
+
+/******************************************************************************/
+
+URLNetFiltering.prototype.fromString = function(text) {
+ var textEnd = text.length;
+ var lineBeg = 0, lineEnd;
+ var line, fields;
+
+ this.reset();
+
+ while ( lineBeg < textEnd ) {
+ lineEnd = text.indexOf('\n', lineBeg);
+ if ( lineEnd < 0 ) {
+ lineEnd = text.indexOf('\r', lineBeg);
+ if ( lineEnd < 0 ) {
+ lineEnd = textEnd;
+ }
+ }
+ line = text.slice(lineBeg, lineEnd).trim();
+ lineBeg = lineEnd + 1;
+
+ if ( line === '' ) {
+ continue;
+ }
+
+ // Coarse test
+ if ( line.indexOf('://') === -1 ) {
+ continue;
+ }
+
+ fields = line.split(/\s+/);
+ if ( fields.length !== 4 ) {
+ continue;
+ }
+
+ // Finer test
+ if ( fields[1].indexOf('://') === -1 ) {
+ continue;
+ }
+
+ if ( nameToActionMap.hasOwnProperty(fields[3]) === false ) {
+ continue;
+ }
+
+ this.setRule(fields[0], fields[1], fields[2], nameToActionMap[fields[3]]);
+ }
+};
+
+/******************************************************************************/
+
+return URLNetFiltering;
+
+/******************************************************************************/
+
+})();
+
+/******************************************************************************/
+
+µBlock.sessionURLFiltering = new µBlock.URLNetFiltering();
+µBlock.permanentURLFiltering = new µBlock.URLNetFiltering();
+
+/******************************************************************************/
diff --git a/src/logger-ui.html b/src/logger-ui.html
index 8ac913c..85cfe30 100644
--- a/src/logger-ui.html
+++ b/src/logger-ui.html
@@ -38,10 +38,21 @@
<div><span>&#xf068;</span>&ensp;<span>&#xf00d;</span></div>
</div>
-<div style="display: none;">
+<div id="templates" style="display: none;">
<div id="renderedURLTemplate"><span><span></span><b></b><span></span></span></div>
<div id="hiddenTemplate"><span style="display:none;"></span></div>
+ <div id="urlFilteringMenu">
+ <div class="dialog">
+ <div>
+ <span class="fa save">&#xf023;</span>
+ <label>Context: <select class="context"></select></label>&emsp;
+ <label>Type: <select class="type"><option><option value="*">*</select></label>
+ </div>
+ <div class="entries"></div>
+ </div>
</div>
+ <div class="urlFilteringMenuEntry"><span class="action"><span class="allow"></span><span class="noop"></span><span class="block"></span></span><span class="url"></span></div>
+</div>
<script src="js/vapi-common.js"></script>
<script src="js/vapi-client.js"></script>