Skip to content

Commit 4eabce4

Browse files
authored
Merge pull request #72 from penge/improve-star-blocking
Allow to block any page containing a word
2 parents e22804d + 2c53812 commit 4eabce4

10 files changed

Lines changed: 117 additions & 91 deletions

File tree

README.md

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,46 +11,47 @@
1111

1212
## Usage
1313

14-
Click on the icon. Enter sites to block. See [Examples](#examples).
14+
Click on the icon. Enter sites to block. See [Special characters](#special-characters) and [Examples](#examples).
1515

1616
Choose how to resolve blocked: **Close Tab**, or **Show Blocked info page**.
1717

1818
**Blocked info page** shows what _url_ was blocked, based on which _rule_ it was blocked, and optionally a blocked count over a chosen period of time:
1919
_All Time_, _This Month_, _This Week_, or _Today_.
2020

21-
### Examples
21+
### Special characters
2222

23-
Block `example.com` **only** (`example.com/apple/` and `orange.example.com` should work):
2423
```
25-
example.com # or example.com/
24+
! ⇒ prepend to exclude from blocking
25+
* ⇒ match any zero or more characters
26+
? ⇒ match any one character
2627
```
2728

28-
<br>
29+
### Examples
2930

30-
Block any page on `example.com` (including `example.com`):
31-
```
32-
example.com/*
3331
```
32+
example.com/ # Blocks example.com/ ONLY
33+
example.com/* # Blocks example.com/ and any page on it
3434
35-
<br>
3635
37-
Block any subdomain of `example.com` **only** (`example.com` should work):
38-
```
39-
*.example.com
40-
```
36+
example.com/* # Blocks any page on example.com/
37+
!example.com/orange/ # except example.com/orange/
4138
42-
<br>
4339
44-
Block any page on `example.com` where first directory starts with any 4 characters (should block `example.com/pear/` or `example.com/plum/`, but not `example.com/orange/`):
45-
```
46-
example.com/????/*
47-
```
40+
*.example.com/ # Blocks any subdomain of example.com/
41+
!apple.example.com/ # except apple.example.com/
4842
49-
<br>
5043
51-
Block any page on `example.com` where first directory starts with any characters but ends with `rry` (should block `example.com/cherry/` or `example.com/strawberry/`, but not `example.com/kiwi/`):
52-
```
53-
example.com/*rry/
44+
*watch* # Blocks any page containing word "watch"
45+
46+
47+
example.com/????/* # Blocks e.g.:
48+
# - example.com/pear/projects/1
49+
# - example.com/plum/projects/1
50+
51+
52+
example.com/*rry/* # Blocks e.g.:
53+
# - example.com/cherry/projects/1
54+
# - example.com/strawberry/projects/1
5455
```
5556

5657
## Privacy notice

public/blocked.css

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,27 @@
11
#url, #rule {
22
font-family: monospace;
3-
opacity: .4;
3+
padding: var(--border-radius);
4+
border-radius: var(--border-radius);
5+
}
6+
7+
#url {
8+
background: #c6c6c6;
9+
color: white;
10+
}
11+
12+
#rule {
13+
background: #ff0100;
14+
color: white;
15+
}
16+
17+
@media (prefers-color-scheme: dark) {
18+
#url {
19+
background: #606060;
20+
color: #121212;
21+
}
22+
23+
#rule {
24+
filter: saturate(50%);
25+
color: #e8e8e8;
26+
}
427
}

public/common.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
:root {
22
--background-color: white;
3+
--border-radius: 3px;
34
--text-color: black;
45
}
56

public/options.css

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
:root {
22
--border-color: black;
3-
--border-radius: 3px;
43
--input-background-color: white;
54
}
65

src/helpers/__tests__/find-rule.test.ts

Lines changed: 58 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,24 @@ import findRule from "../find-rule";
22
import { Rule } from "../make-rules";
33

44
describe("findRule()", () => {
5-
describe("insufficient arguments", () => {
6-
it("returns undefined for empty URL and/or empty blocked", () => {
5+
describe("empty URL and/or empty blocked", () => {
6+
it("returns undefined", () => {
77
expect(findRule("", [])).toBeUndefined();
8-
expect(findRule("", ["example.com"])).toBeUndefined();
8+
expect(findRule("", ["example.com/"])).toBeUndefined();
99
expect(findRule("https://example.com/", [])).toBeUndefined();
1010
});
11+
});
1112

12-
it("returns undefined if domains do not match", () => {
13+
describe("no matching domains", () => {
14+
it("returns undefined", () => {
1315
expect(findRule("https://example.com/", ["something.com"])).toBeUndefined();
16+
expect(findRule("https://example.com/", ["something.com/"])).toBeUndefined();
17+
1418
expect(findRule("https://www.nginx.com/", ["x.com"])).toBeUndefined();
19+
expect(findRule("https://www.nginx.com/", ["x.com/"])).toBeUndefined();
20+
1521
expect(findRule("https://x.com/", ["nginx.com"])).toBeUndefined();
22+
expect(findRule("https://x.com/", ["nginx.com/"])).toBeUndefined();
1623
});
1724
});
1825

@@ -24,49 +31,51 @@ describe("findRule()", () => {
2431

2532
"https://www.example.com/",
2633
"http://www.example.com/",
27-
].forEach((url) => expect(findRule(url, ["example.com"])).toEqual<Rule>({
34+
].forEach((url) => expect(findRule(url, ["example.com/"])).toEqual<Rule>({
2835
type: "block",
29-
path: "example.com",
36+
path: "example.com/",
3037
}));
3138
});
3239
});
3340

3441
describe("domains", () => {
3542
it("can block main domain only", () => {
36-
expect(findRule("https://example.com/", ["example.com"])).toEqual<Rule>({
43+
expect(findRule("https://example.com/", ["example.com"])).toBeUndefined();
44+
expect(findRule("https://example.com/", ["example.com/"])).toEqual<Rule>({
3745
type: "block",
38-
path: "example.com",
46+
path: "example.com/",
3947
});
4048

41-
expect(findRule("https://dashboard.example.com/", ["example.com"])).toBeUndefined();
49+
expect(findRule("https://dashboard.example.com/", ["example.com/"])).toBeUndefined();
4250
});
4351

4452
it("can block subdomain only", () => {
45-
expect(findRule("https://dashboard.example.com/", ["dashboard.example.com"])).toEqual<Rule>({
53+
expect(findRule("https://dashboard.example.com/", ["dashboard.example.com"])).toBeUndefined();
54+
expect(findRule("https://dashboard.example.com/", ["dashboard.example.com/"])).toEqual<Rule>({
4655
type: "block",
47-
path: "dashboard.example.com",
56+
path: "dashboard.example.com/",
4857
});
4958

50-
expect(findRule("https://example.com/", ["dashboard.example.com"])).toBeUndefined();
59+
expect(findRule("https://example.com/", ["dashboard.example.com/"])).toBeUndefined();
5160
});
5261

5362
describe("* in domains", () => {
5463
it("can block any subdomain with *", () => {
5564
[
5665
"https://apple.example.com/",
5766
"https://banana.example.com/",
58-
].forEach((url) => expect(findRule(url, ["*.example.com"])).toEqual<Rule>({
67+
].forEach((url) => expect(findRule(url, ["*.example.com/"])).toEqual<Rule>({
5968
type: "block",
60-
path: "*.example.com",
69+
path: "*.example.com/",
6170
}));
6271

63-
expect(findRule("https://example.com/", ["*.example.com"])).toBeUndefined();
72+
expect(findRule("https://example.com/", ["*.example.com/"])).toBeUndefined();
6473
});
6574
});
6675

6776
describe("? in domains", () => {
6877
it("can block any subdomain of same length defined by ?", () => {
69-
const blocked = ["?????.example.com"];
78+
const blocked = ["?????.example.com/"];
7079

7180
[
7281
"https://mango.example.com/",
@@ -85,16 +94,12 @@ describe("findRule()", () => {
8594
});
8695

8796
describe("paths", () => {
88-
it("can block root path even if / is missing", () => {
97+
it("requires trailing /", () => {
98+
expect(findRule("https://example.com/", ["example.com"])).toBeUndefined();
8999
expect(findRule("https://example.com/", ["example.com/"])).toEqual<Rule>({
90100
type: "block",
91101
path: "example.com/",
92102
});
93-
94-
expect(findRule("https://example.com/", ["example.com"])).toEqual<Rule>({
95-
type: "block",
96-
path: "example.com",
97-
});
98103
});
99104

100105
it("does not block any subpath automatically (without *)", () => {
@@ -103,7 +108,6 @@ describe("findRule()", () => {
103108
"https://example.com/apple/dashboard?tab=analytics#charts",
104109
];
105110

106-
urls.forEach((url) => expect(findRule(url, ["example.com"])).toBeUndefined());
107111
urls.forEach((url) => expect(findRule(url, ["example.com/"])).toBeUndefined());
108112
});
109113

@@ -143,6 +147,23 @@ describe("findRule()", () => {
143147
path: "example.com/*rry/",
144148
}));
145149
});
150+
151+
it("can block any path containing a word", () => {
152+
expect(findRule("https://www.youtube.com/watch?v=123456", ["*watch*"])).toEqual<Rule>({
153+
type: "block",
154+
path: "*watch*",
155+
});
156+
157+
[
158+
"https://www.croxyproxy.com/",
159+
"https://proxyium.com/",
160+
"https://us5.proxysite.one/index.php",
161+
"https://ru.proxy-tools.com/proxy",
162+
].forEach((url) => expect(findRule(url, ["*proxy*"])).toEqual<Rule>({
163+
type: "block",
164+
path: "*proxy*",
165+
}));
166+
});
146167
});
147168

148169
describe("? in paths", () => {
@@ -183,33 +204,36 @@ describe("findRule()", () => {
183204
describe("excluded from blocking", () => {
184205
it("can exclude domain from blocking by prepending !", () => {
185206
const blockedExcludedDomain = [
186-
"*.example.com",
187-
"!apple.example.com",
207+
"*.example.com/",
208+
"!apple.example.com/",
188209
];
189210

190-
expect(findRule("https://apple.example.com/", blockedExcludedDomain)).toEqual<Rule>({
191-
type: "allow",
192-
path: "apple.example.com",
193-
});
194-
195211
expect(findRule("https://banana.example.com/", blockedExcludedDomain)).toEqual<Rule>({
196212
type: "block",
197-
path: "*.example.com",
213+
path: "*.example.com/",
214+
});
215+
216+
expect(findRule("https://apple.example.com/", blockedExcludedDomain)).toEqual<Rule>({
217+
type: "allow",
218+
path: "apple.example.com/",
198219
});
199220
});
200221

201222
it("can exclude path from blocking by prepending !", () => {
202223
const blockedExcludedPath = [
203-
"example.com",
224+
"example.com/*",
204225
"!example.com/strawberry/",
205226
];
206227

228+
expect(findRule("https://example.com/apple/", blockedExcludedPath)).toEqual<Rule>({
229+
type: "block",
230+
path: "example.com/*",
231+
});
232+
207233
expect(findRule("https://example.com/strawberry/", blockedExcludedPath)).toEqual<Rule>({
208234
type: "allow",
209235
path: "example.com/strawberry/",
210236
});
211-
212-
expect(findRule("https://example.com/orange/", blockedExcludedPath)).toBeUndefined();
213237
});
214238
});
215239
});

src/helpers/__tests__/get-blocked-message.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ test("getBlockedMessage() returns blocked message", () => {
44
expect(getBlockedMessage({
55
url: "http://youtube.com/",
66
rule: "youtube.com",
7-
})).toBe('<span id="url">http://youtube.com/</span> <b>was blocked</b> by rule <span id="rule">youtube.com</span>');
7+
})).toBe('<span id="url">http://youtube.com/</span> <b>was blocked</b> by <span id="rule">youtube.com</span>');
88

99
expect(getBlockedMessage({
1010
url: "http://youtube.com/",
@@ -13,7 +13,7 @@ test("getBlockedMessage() returns blocked message", () => {
1313
count: 42,
1414
period: "ALL_TIME",
1515
},
16-
})).toBe('<span id="url">http://youtube.com/</span> <b>was blocked</b> (42x overall) by rule <span id="rule">youtube.com</span>');
16+
})).toBe('<span id="url">http://youtube.com/</span> <b>was blocked</b> by <span id="rule">youtube.com</span> (42x overall)');
1717

1818
expect(getBlockedMessage({
1919
url: "http://youtube.com/",
@@ -22,7 +22,7 @@ test("getBlockedMessage() returns blocked message", () => {
2222
count: 5,
2323
period: "TODAY",
2424
},
25-
})).toBe('<span id="url">http://youtube.com/</span> <b>was blocked</b> (5x today) by rule <span id="rule">youtube.com</span>');
25+
})).toBe('<span id="url">http://youtube.com/</span> <b>was blocked</b> by <span id="rule">youtube.com</span> (5x today)');
2626

2727
expect(getBlockedMessage({
2828
url: "http://youtube.com/",
@@ -31,7 +31,7 @@ test("getBlockedMessage() returns blocked message", () => {
3131
count: 12,
3232
period: "THIS_WEEK",
3333
},
34-
})).toBe('<span id="url">http://youtube.com/</span> <b>was blocked</b> (12x this week) by rule <span id="rule">youtube.com</span>');
34+
})).toBe('<span id="url">http://youtube.com/</span> <b>was blocked</b> by <span id="rule">youtube.com</span> (12x this week)');
3535

3636
expect(getBlockedMessage({
3737
url: "http://youtube.com/",
@@ -40,5 +40,5 @@ test("getBlockedMessage() returns blocked message", () => {
4040
count: 38,
4141
period: "THIS_MONTH",
4242
},
43-
})).toBe('<span id="url">http://youtube.com/</span> <b>was blocked</b> (38x this month) by rule <span id="rule">youtube.com</span>');
43+
})).toBe('<span id="url">http://youtube.com/</span> <b>was blocked</b> by <span id="rule">youtube.com</span> (38x this month)');
4444
});

src/helpers/__tests__/normalize-url.test.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import normalizeUrl, { appendTrailingSlashIfMissing } from "../normalize-url";
1+
import normalizeUrl from "../normalize-url";
22

33
describe("normalizeUrl()", () => {
44
it("removes https, http, www", () => {
@@ -33,10 +33,3 @@ describe("normalizeUrl()", () => {
3333
);
3434
});
3535
});
36-
37-
describe("appendTrailingSlashIfMissing()", () => {
38-
it("appends trailing slash if missing", () => {
39-
expect(appendTrailingSlashIfMissing("example.com")).toBe("example.com/");
40-
expect(appendTrailingSlashIfMissing("example.com/")).toBe("example.com/");
41-
});
42-
});

src/helpers/find-rule.ts

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import normalizeUrl, { appendTrailingSlashIfMissing } from "./normalize-url";
1+
import normalizeUrl from "./normalize-url";
22
import makeRules, { Rule } from "./make-rules";
33

44
export default (url: string, blocked: string[]): Rule | undefined => {
@@ -8,20 +8,7 @@ export default (url: string, blocked: string[]): Rule | undefined => {
88
const foundRule = rules.find((rule) =>
99
normalizedUrl.match(new RegExp(
1010
"^"
11-
/**
12-
* To make it convenient for the user to block the root path (homepage),
13-
* he can type either of:
14-
* - example.com
15-
* - example.com/
16-
* and they both will work.
17-
*
18-
* To make this work, we append trailing slash if missing, and
19-
* use that for the pattern matching.
20-
*
21-
* The original rule in "rules" remains unchanged,
22-
* because it is the rule we would like to show to the user if blocked.
23-
*/
24-
+ appendTrailingSlashIfMissing(rule.path)
11+
+ rule.path
2512
.replace(/\?/g, ".") // user can type "?" to match any one character
2613
.replace(/\*/g, ".*") // user can type "*" to match any zero or more characters
2714
+ "$",

0 commit comments

Comments
 (0)