Skip to content

Commit

Permalink
Allow to block any page containing a word
Browse files Browse the repository at this point in the history
- do not add trailing / automatically anymore
- update README (list Special characters, update Examples)
  • Loading branch information
penge committed Dec 29, 2023
1 parent e22804d commit 9a48cfb
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 77 deletions.
54 changes: 32 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,46 +11,56 @@

## 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/ # Block example.com/ ONLY
# Do NOT block:
# - example.com/apple/
# - orange.example.com/
<br>
Block any subdomain of `example.com` **only** (`example.com` should work):
```
*.example.com
```
example.com/* # Block example.com/ and any subpage
<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/ # Block any subdomain of example.com/ ONLY
# Block: orange.example.com/
# Do NOT block: 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/
example.com/* # Block: example.com/apple/
!example.com/orange/ # Do NOT block: example.com/orange/
*.example.com/ # Block: banana.example.com/
!apple.example.com/ # Do NOT block: apple.example.com/
*watch* # Block any page containing word "watch"
# Block: example.com/watch?v=123456
example.com/????/* # Block: example.com/pear/
# Do NOT block: example.com/orange/
example.com/*rry/ # Block: example.com/cherry/
# Do NOT block: example.com/kiwi/
```

## Privacy notice
Expand Down
88 changes: 58 additions & 30 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 @@ -91,9 +100,9 @@ describe("findRule()", () => {
path: "example.com/",
});

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

Expand All @@ -103,7 +112,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 +151,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 +208,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();
});
});
});
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
2 changes: 0 additions & 2 deletions src/helpers/normalize-url.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,3 @@ export default (url: string): string => [url]
.map(__removeProtocol)
.map(__removeWww)
.pop() as string;

export const appendTrailingSlashIfMissing = (url: string) => url.split("/").length === 1 ? `${url}/` : url;

0 comments on commit 9a48cfb

Please sign in to comment.