Skip to content

Commit

Permalink
Merge pull request #72 from penge/improve-star-blocking
Browse files Browse the repository at this point in the history
Allow to block any page containing a word
  • Loading branch information
penge committed Dec 29, 2023
2 parents e22804d + 2c53812 commit 4eabce4
Show file tree
Hide file tree
Showing 10 changed files with 117 additions and 91 deletions.
45 changes: 23 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,46 +11,47 @@

## Usage

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

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

**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:
_All Time_, _This Month_, _This Week_, or _Today_.

### Examples
### Special characters

Block `example.com` **only** (`example.com/apple/` and `orange.example.com` should work):
```
example.com # or example.com/
! ⇒ prepend to exclude from blocking
* ⇒ match any zero or more characters
? ⇒ match any one character
```

<br>
### Examples

Block any page on `example.com` (including `example.com`):
```
example.com/*
```
example.com/ # Blocks example.com/ ONLY
example.com/* # Blocks example.com/ and any page on it
<br>
Block any subdomain of `example.com` **only** (`example.com` should work):
```
*.example.com
```
example.com/* # Blocks any page on example.com/
!example.com/orange/ # except example.com/orange/
<br>
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/`):
```
example.com/????/*
```
*.example.com/ # Blocks any subdomain of example.com/
!apple.example.com/ # except apple.example.com/
<br>
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/`):
```
example.com/*rry/
*watch* # Blocks any page containing word "watch"
example.com/????/* # Blocks e.g.:
# - example.com/pear/projects/1
# - example.com/plum/projects/1
example.com/*rry/* # Blocks e.g.:
# - example.com/cherry/projects/1
# - example.com/strawberry/projects/1
```

## Privacy notice
Expand Down
25 changes: 24 additions & 1 deletion public/blocked.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,27 @@
#url, #rule {
font-family: monospace;
opacity: .4;
padding: var(--border-radius);
border-radius: var(--border-radius);
}

#url {
background: #c6c6c6;
color: white;
}

#rule {
background: #ff0100;
color: white;
}

@media (prefers-color-scheme: dark) {
#url {
background: #606060;
color: #121212;
}

#rule {
filter: saturate(50%);
color: #e8e8e8;
}
}
1 change: 1 addition & 0 deletions public/common.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
:root {
--background-color: white;
--border-radius: 3px;
--text-color: black;
}

Expand Down
1 change: 0 additions & 1 deletion public/options.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
:root {
--border-color: black;
--border-radius: 3px;
--input-background-color: white;
}

Expand Down
92 changes: 58 additions & 34 deletions src/helpers/__tests__/find-rule.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,24 @@ import findRule from "../find-rule";
import { Rule } from "../make-rules";

describe("findRule()", () => {
describe("insufficient arguments", () => {
it("returns undefined for empty URL and/or empty blocked", () => {
describe("empty URL and/or empty blocked", () => {
it("returns undefined", () => {
expect(findRule("", [])).toBeUndefined();
expect(findRule("", ["example.com"])).toBeUndefined();
expect(findRule("", ["example.com/"])).toBeUndefined();
expect(findRule("https://example.com/", [])).toBeUndefined();
});
});

it("returns undefined if domains do not match", () => {
describe("no matching domains", () => {
it("returns undefined", () => {
expect(findRule("https://example.com/", ["something.com"])).toBeUndefined();
expect(findRule("https://example.com/", ["something.com/"])).toBeUndefined();

expect(findRule("https://www.nginx.com/", ["x.com"])).toBeUndefined();
expect(findRule("https://www.nginx.com/", ["x.com/"])).toBeUndefined();

expect(findRule("https://x.com/", ["nginx.com"])).toBeUndefined();
expect(findRule("https://x.com/", ["nginx.com/"])).toBeUndefined();
});
});

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

"https://www.example.com/",
"http://www.example.com/",
].forEach((url) => expect(findRule(url, ["example.com"])).toEqual<Rule>({
].forEach((url) => expect(findRule(url, ["example.com/"])).toEqual<Rule>({
type: "block",
path: "example.com",
path: "example.com/",
}));
});
});

describe("domains", () => {
it("can block main domain only", () => {
expect(findRule("https://example.com/", ["example.com"])).toEqual<Rule>({
expect(findRule("https://example.com/", ["example.com"])).toBeUndefined();
expect(findRule("https://example.com/", ["example.com/"])).toEqual<Rule>({
type: "block",
path: "example.com",
path: "example.com/",
});

expect(findRule("https://dashboard.example.com/", ["example.com"])).toBeUndefined();
expect(findRule("https://dashboard.example.com/", ["example.com/"])).toBeUndefined();
});

it("can block subdomain only", () => {
expect(findRule("https://dashboard.example.com/", ["dashboard.example.com"])).toEqual<Rule>({
expect(findRule("https://dashboard.example.com/", ["dashboard.example.com"])).toBeUndefined();
expect(findRule("https://dashboard.example.com/", ["dashboard.example.com/"])).toEqual<Rule>({
type: "block",
path: "dashboard.example.com",
path: "dashboard.example.com/",
});

expect(findRule("https://example.com/", ["dashboard.example.com"])).toBeUndefined();
expect(findRule("https://example.com/", ["dashboard.example.com/"])).toBeUndefined();
});

describe("* in domains", () => {
it("can block any subdomain with *", () => {
[
"https://apple.example.com/",
"https://banana.example.com/",
].forEach((url) => expect(findRule(url, ["*.example.com"])).toEqual<Rule>({
].forEach((url) => expect(findRule(url, ["*.example.com/"])).toEqual<Rule>({
type: "block",
path: "*.example.com",
path: "*.example.com/",
}));

expect(findRule("https://example.com/", ["*.example.com"])).toBeUndefined();
expect(findRule("https://example.com/", ["*.example.com/"])).toBeUndefined();
});
});

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

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

describe("paths", () => {
it("can block root path even if / is missing", () => {
it("requires trailing /", () => {
expect(findRule("https://example.com/", ["example.com"])).toBeUndefined();
expect(findRule("https://example.com/", ["example.com/"])).toEqual<Rule>({
type: "block",
path: "example.com/",
});

expect(findRule("https://example.com/", ["example.com"])).toEqual<Rule>({
type: "block",
path: "example.com",
});
});

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

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

Expand Down Expand Up @@ -143,6 +147,23 @@ describe("findRule()", () => {
path: "example.com/*rry/",
}));
});

it("can block any path containing a word", () => {
expect(findRule("https://www.youtube.com/watch?v=123456", ["*watch*"])).toEqual<Rule>({
type: "block",
path: "*watch*",
});

[
"https://www.croxyproxy.com/",
"https://proxyium.com/",
"https://us5.proxysite.one/index.php",
"https://ru.proxy-tools.com/proxy",
].forEach((url) => expect(findRule(url, ["*proxy*"])).toEqual<Rule>({
type: "block",
path: "*proxy*",
}));
});
});

describe("? in paths", () => {
Expand Down Expand Up @@ -183,33 +204,36 @@ describe("findRule()", () => {
describe("excluded from blocking", () => {
it("can exclude domain from blocking by prepending !", () => {
const blockedExcludedDomain = [
"*.example.com",
"!apple.example.com",
"*.example.com/",
"!apple.example.com/",
];

expect(findRule("https://apple.example.com/", blockedExcludedDomain)).toEqual<Rule>({
type: "allow",
path: "apple.example.com",
});

expect(findRule("https://banana.example.com/", blockedExcludedDomain)).toEqual<Rule>({
type: "block",
path: "*.example.com",
path: "*.example.com/",
});

expect(findRule("https://apple.example.com/", blockedExcludedDomain)).toEqual<Rule>({
type: "allow",
path: "apple.example.com/",
});
});

it("can exclude path from blocking by prepending !", () => {
const blockedExcludedPath = [
"example.com",
"example.com/*",
"!example.com/strawberry/",
];

expect(findRule("https://example.com/apple/", blockedExcludedPath)).toEqual<Rule>({
type: "block",
path: "example.com/*",
});

expect(findRule("https://example.com/strawberry/", blockedExcludedPath)).toEqual<Rule>({
type: "allow",
path: "example.com/strawberry/",
});

expect(findRule("https://example.com/orange/", blockedExcludedPath)).toBeUndefined();
});
});
});
10 changes: 5 additions & 5 deletions src/helpers/__tests__/get-blocked-message.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ test("getBlockedMessage() returns blocked message", () => {
expect(getBlockedMessage({
url: "http://youtube.com/",
rule: "youtube.com",
})).toBe('<span id="url">http://youtube.com/</span> <b>was blocked</b> by rule <span id="rule">youtube.com</span>');
})).toBe('<span id="url">http://youtube.com/</span> <b>was blocked</b> by <span id="rule">youtube.com</span>');

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

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

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

expect(getBlockedMessage({
url: "http://youtube.com/",
Expand All @@ -40,5 +40,5 @@ test("getBlockedMessage() returns blocked message", () => {
count: 38,
period: "THIS_MONTH",
},
})).toBe('<span id="url">http://youtube.com/</span> <b>was blocked</b> (38x this month) by rule <span id="rule">youtube.com</span>');
})).toBe('<span id="url">http://youtube.com/</span> <b>was blocked</b> by <span id="rule">youtube.com</span> (38x this month)');
});
9 changes: 1 addition & 8 deletions src/helpers/__tests__/normalize-url.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import normalizeUrl, { appendTrailingSlashIfMissing } from "../normalize-url";
import normalizeUrl from "../normalize-url";

describe("normalizeUrl()", () => {
it("removes https, http, www", () => {
Expand Down Expand Up @@ -33,10 +33,3 @@ describe("normalizeUrl()", () => {
);
});
});

describe("appendTrailingSlashIfMissing()", () => {
it("appends trailing slash if missing", () => {
expect(appendTrailingSlashIfMissing("example.com")).toBe("example.com/");
expect(appendTrailingSlashIfMissing("example.com/")).toBe("example.com/");
});
});
17 changes: 2 additions & 15 deletions src/helpers/find-rule.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import normalizeUrl, { appendTrailingSlashIfMissing } from "./normalize-url";
import normalizeUrl from "./normalize-url";
import makeRules, { Rule } from "./make-rules";

export default (url: string, blocked: string[]): Rule | undefined => {
Expand All @@ -8,20 +8,7 @@ export default (url: string, blocked: string[]): Rule | undefined => {
const foundRule = rules.find((rule) =>
normalizedUrl.match(new RegExp(
"^"
/**
* To make it convenient for the user to block the root path (homepage),
* he can type either of:
* - example.com
* - example.com/
* and they both will work.
*
* To make this work, we append trailing slash if missing, and
* use that for the pattern matching.
*
* The original rule in "rules" remains unchanged,
* because it is the rule we would like to show to the user if blocked.
*/
+ appendTrailingSlashIfMissing(rule.path)
+ rule.path
.replace(/\?/g, ".") // user can type "?" to match any one character
.replace(/\*/g, ".*") // user can type "*" to match any zero or more characters
+ "$",
Expand Down
Loading

0 comments on commit 4eabce4

Please sign in to comment.