Skip to content

Commit 3d1c38a

Browse files
committed
Partially revert EFForg#3883.
This caused a regression: Rules that are active but not taking effect (formerly moot rules) are simply not listed, when my intention was to list them (i.e., match the Chrome behavior). Will roll forward again when I have a fix, but didn't want to leave things in a broken state until then. This is a partial revert because the Chrome changes were fine, so I'm leaving them.
1 parent 12c1930 commit 3d1c38a

File tree

10 files changed

+132
-20
lines changed

10 files changed

+132
-20
lines changed

src/chrome/content/code/AndroidUI.jsm

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@ var popupInfo = {
106106
this.ruleItems.push({ label: rule, selected: true });
107107
this.ruleStatus.push(true);
108108
this.rules.push(this.alist.active[rule]);
109+
} else if (this.alist.moot.hasOwnProperty(rule)) {
110+
// moot rules are checked and toggleable too
111+
this.ruleItems.push({ label: rule, selected: true });
112+
this.ruleStatus.push(true);
113+
this.rules.push(this.alist.moot[rule]);
109114
} else if (this.alist.inactive.hasOwnProperty(rule)) {
110115
// inactive rules are unchecked and toggleable
111116
this.ruleItems.push({ label: rule });

src/chrome/content/code/ApplicableList.js

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ function ApplicableList(logger, uri) {
1717
this.active = {};
1818
this.breaking = {}; // rulesets with redirection loops
1919
this.inactive = {};
20-
this.all={}; // active + breaking + inactive
20+
this.moot={}; // rulesets that might be applicable but uris are already https
21+
this.all={}; // active + breaking + inactive + moot
2122
serial_number += 1;
2223
this.serial = serial_number;
2324
this.log(DBUG,"Alist serial #" + this.serial + " for " + this.home);
@@ -31,6 +32,7 @@ ApplicableList.prototype = {
3132
this.active = {};
3233
this.breaking = {};
3334
this.inactive = {};
35+
this.moot={};
3436
this.all={};
3537
},
3638

@@ -56,6 +58,12 @@ ApplicableList.prototype = {
5658
this.all[ruleset.name] = ruleset;
5759
},
5860

61+
moot_rule: function(ruleset) {
62+
this.log(INFO,"moot rule " + ruleset.name +" in "+ this.home + " serial " + this.serial);
63+
this.moot[ruleset.name] = ruleset;
64+
this.all[ruleset.name] = ruleset;
65+
},
66+
5967
dom_handler: function(operation,key,data,src,dst) {
6068
// See https://developer.mozilla.org/En/DOM/UserDataHandler
6169
if (src && dst)
@@ -174,13 +182,19 @@ ApplicableList.prototype = {
174182
this.add_command(this.breaking[x]);
175183
for(var x in this.active)
176184
this.add_command(this.active[x]);
185+
for(var x in this.moot)
186+
this.add_command(this.moot[x]);
177187
for(var x in this.inactive)
178188
this.add_command(this.inactive[x]);
179189

180190
if(https_everywhere.prefs.getBoolPref("globalEnabled")){
181191
// add all the menu items
182192
for (var x in this.inactive)
183193
this.add_menuitem(this.inactive[x], 'inactive');
194+
// rules that are active for some uris are not really moot
195+
for (var x in this.moot)
196+
if (!(x in this.active))
197+
this.add_menuitem(this.moot[x], 'moot');
184198
// break once break everywhere
185199
for (var x in this.active)
186200
if (!(x in this.breaking))
@@ -206,8 +220,9 @@ ApplicableList.prototype = {
206220
this.commandset.appendChild(command);
207221
},
208222

209-
// add a menu item for a rule -- type is "active", "inactive"
223+
// add a menu item for a rule -- type is "active", "inactive", "moot",
210224
// or "breaking"
225+
211226
add_menuitem: function(rule, type) {
212227
// create the menuitem
213228
var item = this.document.createElement('menuitem');
@@ -218,20 +233,37 @@ ApplicableList.prototype = {
218233

219234
// we can get confused if rulesets have their state changed after the
220235
// ApplicableList was constructed
221-
if (!rule.active && (type == 'active'))
236+
if (!rule.active && (type == 'active' || type == 'moot'))
222237
type = 'inactive';
223238
if (rule.active && type == 'inactive')
224-
type = 'active';
225-
239+
type = 'moot';
240+
226241
// set the icon
227242
var image_src;
228243
if (type == 'active') image_src = 'tick.png';
229244
else if (type == 'inactive') image_src = 'cross.png';
245+
else if (type == 'moot') image_src = 'tick-moot.png';
230246
else if (type == 'breaking') image_src = 'loop.png';
231247
item.setAttribute('image', 'chrome://https-everywhere/skin/'+image_src);
232248

233249
// all done
234250
this.prepend_child(item);
251+
},
252+
253+
show_applicable: function() {
254+
this.log(WARN, "Applicable list number " + this.serial);
255+
for (var x in this.active)
256+
this.log(WARN,"Active: " + this.active[x].name);
257+
258+
for (var x in this.breaking)
259+
this.log(WARN,"Breaking: " + this.breaking[x].name);
260+
261+
for (x in this.inactive)
262+
this.log(WARN,"Inactive: " + this.inactive[x].name);
263+
264+
for (x in this.moot)
265+
this.log(WARN,"Moot: " + this.moot[x].name);
266+
235267
}
236268
};
237269

src/chrome/content/code/HTTPSRules.js

Lines changed: 64 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,20 @@ function CookieRule(host, cookiename) {
1919
//this.name_c = new RegExp(cookiename);
2020
}
2121

22-
function RuleSet(id, name, default_off, platform) {
22+
function RuleSet(id, name, xmlName, match_rule, default_off, platform) {
23+
if(xmlName == "WordPress.xml" || xmlName == "Github.xml") {
24+
this.log(NOTE, "RuleSet( name="+name+", xmlName="+xmlName+", match_rule="+match_rule+", default_off="+default_off+", platform="+platform+" )");
25+
}
26+
2327
this.id=id;
2428
this.on_by_default = true;
2529
this.compiled = false;
2630
this.name = name;
31+
this.xmlName = xmlName;
2732
this.notes = "";
2833

34+
if (match_rule) this.ruleset_match_c = new RegExp(match_rule);
35+
else this.ruleset_match_c = null;
2936
if (default_off) {
3037
// Perhaps problematically, this currently ignores the actual content of
3138
// the default_off XML attribute. Ideally we'd like this attribute to be
@@ -86,7 +93,12 @@ RuleSet.prototype = {
8693
var i;
8794
var returl = null;
8895
this.ensureCompiled();
89-
// If we're covered by an exclusion, go home
96+
// If a rulset has a match_rule and it fails, go no further
97+
if (this.ruleset_match_c && !this.ruleset_match_c.test(urispec)) {
98+
this.log(VERB, "ruleset_match_c excluded " + urispec);
99+
return null;
100+
}
101+
// Even so, if we're covered by an exclusion, go home
90102
for (i = 0; i < this.exclusions.length; ++i) {
91103
if (this.exclusions[i].pattern_c.test(urispec)) {
92104
this.log(DBUG,"excluded uri " + urispec);
@@ -99,7 +111,7 @@ RuleSet.prototype = {
99111
returl = urispec.replace(this.rules[i].from_c, this.rules[i].to);
100112
if (returl != urispec) {
101113
// we rewrote the uri
102-
this.log(DBUG, "Rewrote " + urispec + " -> " + returl + " using " + this.name + ": " + this.rules[i].from_c + " -> " + this.rules[i].to);
114+
this.log(DBUG, "Rewrote " + urispec + " -> " + returl + " using " + this.xmlName + ": " + this.rules[i].from_c + " -> " + this.rules[i].to);
103115
return returl;
104116
}
105117
}
@@ -109,6 +121,35 @@ RuleSet.prototype = {
109121
log: function(level, msg) {
110122
https_everywhereLog(level, msg);
111123
},
124+
125+
wouldMatch: function(hypothetical_uri, alist) {
126+
// return true if this ruleset would match the uri, assuming it were http
127+
// used for judging moot / inactive rulesets
128+
// alist is optional
129+
130+
// if the ruleset is already somewhere in this applicable list, we don't
131+
// care about hypothetical wouldMatch questions
132+
if (alist && (this.name in alist.all)) return false;
133+
134+
this.log(DBUG,"Would " +this.name + " match " +hypothetical_uri.spec +
135+
"? serial " + (alist && alist.serial));
136+
137+
var uri = hypothetical_uri.clone();
138+
if (uri.scheme == "https") uri.scheme = "http";
139+
var urispec = uri.spec;
140+
141+
this.ensureCompiled();
142+
143+
if (this.ruleset_match_c && !this.ruleset_match_c.test(urispec))
144+
return false;
145+
146+
for (var i = 0; i < this.exclusions.length; ++i)
147+
if (this.exclusions[i].pattern_c.test(urispec)) return false;
148+
149+
for (var i = 0; i < this.rules.length; ++i)
150+
if (this.rules[i].from_c.test(urispec)) return true;
151+
return false;
152+
},
112153

113154
transformURI: function(uri) {
114155
// If no rule applies, return null; if a rule would have applied but was
@@ -268,9 +309,10 @@ const RuleWriter = {
268309

269310
this.log(DBUG, "Parsing " + xmlruleset.getAttribute("name"));
270311

312+
var match_rl = xmlruleset.getAttribute("match_rule");
271313
var dflt_off = xmlruleset.getAttribute("default_off");
272314
var platform = xmlruleset.getAttribute("platform");
273-
var rs = new RuleSet(ruleset_id, xmlruleset.getAttribute("name"), dflt_off, platform);
315+
var rs = new RuleSet(ruleset_id, xmlruleset.getAttribute("name"), xmlruleset.getAttribute("f"), match_rl, dflt_off, platform);
274316

275317
// see if this ruleset has the same name as an existing ruleset;
276318
// if so, this ruleset is ignored; DON'T add or return it.
@@ -456,26 +498,31 @@ const HTTPSRules = {
456498
}
457499

458500
// ponder each potentially applicable ruleset, working out if it applies
459-
// and recording it as active/inactive/breaking in the applicable list
501+
// and recording it as active/inactive/moot/breaking in the applicable list
460502
for (i = 0; i < rs.length; ++i) {
461503
if (!rs[i].active) {
462-
alist.inactive_rule(rs[i]);
463-
}
504+
if (alist && rs[i].wouldMatch(uri, alist))
505+
alist.inactive_rule(rs[i]);
506+
continue;
507+
}
464508
blob.newuri = rs[i].transformURI(uri);
465509
if (blob.newuri) {
466510
if (alist) {
467-
if (uri.spec in https_everywhere_blacklist) {
511+
if (uri.spec in https_everywhere_blacklist)
468512
alist.breaking_rule(rs[i]);
469-
} else {
513+
else
470514
alist.active_rule(rs[i]);
471-
}
472-
}
473-
if (userpass_present) {
474-
blob.newuri.userPass = input_uri.userPass;
475-
}
515+
}
516+
if (userpass_present) blob.newuri.userPass = input_uri.userPass;
476517
blob.applied_ruleset = rs[i];
477518
return blob;
478519
}
520+
if (uri.scheme == "https" && alist) {
521+
// we didn't rewrite but the rule applies to this domain and the
522+
// requests are going over https
523+
if (rs[i].wouldMatch(uri, alist)) alist.moot_rule(rs[i]);
524+
continue;
525+
}
479526
}
480527
return null;
481528
},
@@ -662,6 +709,9 @@ const HTTPSRules = {
662709
return true;
663710
}
664711
}
712+
if (ruleset.cookierules.length > 0 && applicable_list) {
713+
applicable_list.moot_rule(ruleset);
714+
}
665715
} else if (ruleset.cookierules.length > 0) {
666716
if (applicable_list) {
667717
applicable_list.inactive_rule(ruleset);

src/chrome/content/toolbar_button.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,11 @@ httpsEverywhere.toolbarButton = {
198198
++counter;
199199
}
200200
}
201+
for (var x in alist.moot) {
202+
if (!(x in alist.active)) {
203+
++counter;
204+
}
205+
}
201206

202207
toolbarbutton.setAttribute('rulesetsApplied', counter);
203208
HTTPSEverywhere.log(INFO, 'Setting icon counter to: ' + counter);

src/chrome/skin/https-everywhere.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ toolbar[iconsize="small"] #https-everywhere-button[status="disabled"] > .https-e
6868
color: #1e6419;
6969
font-weight: bold;
7070
}
71+
#https-everywhere-button menuitem.moot-item label {
72+
color: #1e6419;
73+
opacity: 0.75;
74+
font-weight: bold;
75+
}
7176
#https-everywhere-button menuitem.breaking-item label {
7277
color: #b99999;
7378
font-weight: bold;

utils/make-sqlite.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@
8181
# pointing into the ruleset table.
8282
etree.strip_tags(tree, 'target')
8383

84+
# Store the filename in the `f' attribute so "view source XML" for rules in
85+
# FF version can find it.
86+
xpath_ruleset(tree)[0].attrib["f"] = os.path.basename(fi).decode(encoding="UTF-8")
87+
8488
c.execute('''INSERT INTO rulesets (contents) VALUES(?)''', (etree.tostring(tree),))
8589
ruleset_id = c.lastrowid
8690
for target in targets:

utils/merge-rulesets.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,13 @@ def clean_up(rulefile):
7272
# Chromium
7373
library.write('<rulesetlibrary>')
7474

75+
# Include the filename.xml as the "f" attribute
7576
print("Removing whitespaces and comments...")
7677

7778
for rfile in sorted(xml_ruleset_files):
7879
ruleset = open(rfile).read()
80+
fn = os.path.basename(rfile)
81+
ruleset = ruleset.replace("<ruleset", '<ruleset f="%s"' % fn, 1)
7982
library.write(clean_up(ruleset))
8083
library.write("</rulesetlibrary>\n")
8184
library.close()

utils/relaxng.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
<element xmlns="http://relaxng.org/ns/structure/1.0" name="ruleset" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
22
<attribute name="name" />
33

4+
<optional>
5+
<attribute name="match_rule" />
6+
</optional>
7+
48
<optional>
59
<attribute name="default_off" />
610
</optional>

utils/simple.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ def simple(f):
1818
return all([
1919
# ruleset must not be default_off
2020
"default_off" not in tree.xpath("/ruleset")[0].attrib,
21+
# ruleset must not contain a match_rule
22+
"match_rule" not in tree.xpath("/ruleset")[0].attrib,
2123
# XXX: maybe also check for platform="mixedcontent" here
2224
# ruleset must not apply any securecookie patterns
2325
not tree.xpath("/ruleset/securecookie"),

utils/trivial-validate.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ def nomes_all(where=sys.argv[1:]):
160160

161161
xpath_ruleset = etree.XPath("/ruleset")
162162
xpath_ruleset_name = etree.XPath("/ruleset/@name")
163+
xpath_ruleset_file = etree.XPath("/ruleset/@f")
163164
xpath_host = etree.XPath("/ruleset/target/@host")
164165
xpath_from = etree.XPath("/ruleset/rule/@from")
165166
xpath_to = etree.XPath("/ruleset/rule/@to")
@@ -179,12 +180,13 @@ def nomes_all(where=sys.argv[1:]):
179180
failure = 1
180181
fail("unnamed ruleset")
181182
continue
183+
rf = xpath_ruleset_file(tree)[0]
182184
from_attrib = xpath_from(tree)
183185
to = xpath_to(tree)
184186
for test in tests:
185187
if not test(tree, rn, from_attrib=from_attrib, to=to):
186188
failure = 1
187-
fail("%s failed test: %s" % (rn, test.__doc__))
189+
fail("%s failed test: %s" % (rf, test.__doc__))
188190

189191
for (host, count) in c.execute('''
190192
select host, count(host) as c from targets group by host;'''):

0 commit comments

Comments
 (0)