Skip to content

Commit

Permalink
Block www using *
Browse files Browse the repository at this point in the history
- can block only www paths
- www blocked by default (for convenience)
- adding /* to paths, if there is no / (for convenience)
- escaping regex-like characters in paths (. and +)
  • Loading branch information
penge committed Apr 25, 2024
1 parent 02d6532 commit ebe7c7a
Show file tree
Hide file tree
Showing 10 changed files with 132 additions and 68 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ _All Time_, _This Month_, _This Week_, or _Today_.
### Examples

```
example.com # Blocks example.com/ and any page on it
example.com/ # Blocks example.com/ ONLY
example.com/* # Blocks example.com/ and any page on it
Expand Down
58 changes: 47 additions & 11 deletions src/helpers/__tests__/find-rule.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ describe("findRule()", () => {

describe("domains", () => {
it("can block main domain only", () => {
expect(findRule("https://example.com/", ["example.com"])).toBeUndefined();
expect(findRule("https://example.com/", ["example.com/"])).toEqual<Rule>({
type: "block",
path: "example.com/",
Expand All @@ -50,7 +49,6 @@ describe("findRule()", () => {
});

it("can block subdomain only", () => {
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/",
Expand All @@ -71,6 +69,20 @@ describe("findRule()", () => {

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

it("can block www subdomain with *", () => {
const blocked = ["*.facebook.com/*", "www.facebook.com/*"];
blocked.forEach((blocked) => {
expect(findRule("https://www.facebook.com/", [blocked])).toEqual<Rule>({
type: "block",
path: blocked,
});
});

blocked.forEach((blocked) => {
expect(findRule("https://facebook.com/", [blocked])).toBeUndefined();
});
});
});

describe("? in domains", () => {
Expand All @@ -94,21 +106,45 @@ describe("findRule()", () => {
});

describe("paths", () => {
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/",
it("expands with www. if path does not start with www. or *.", () => {
const blocked = ["facebook.com/*", "*.facebook.com/*", "www.facebook.com/*"];
blocked.forEach((blocked) => {
expect(findRule("https://www.facebook.com/", [blocked])).toEqual<Rule>({
type: "block",
path: blocked,
});
});
});

it("expands with /* if there is no /", () => {
[
"https://example.com/",
"https://example.com/pear/projects/1",
].forEach((url) => {
expect(findRule(url, ["example.com"])).toEqual<Rule>({
type: "block",
path: "example.com",
});
});

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

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

it("does not block any subpath automatically (without *)", () => {
const urls = [
[
"https://example.com/apple/",
"https://example.com/apple/dashboard?tab=analytics#charts",
];

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

describe("* in paths", () => {
Expand Down
6 changes: 6 additions & 0 deletions src/helpers/__tests__/make-rules.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import makeRules, { Rule } from "../make-rules";
test("makeRules()", () => {
expect(
makeRules([
"www.facebook.com",
"https://www.instagram.com/",

"*.youtube.com",
"!music.youtube.com",

Expand All @@ -13,6 +16,9 @@ test("makeRules()", () => {
{ type: "allow", path: "music.youtube.com" },
{ type: "allow", path: "reddit.com/r/MachineLearning" },

{ type: "block", path: "www.facebook.com" },
{ type: "block", path: "www.instagram.com/" },

{ type: "block", path: "*.youtube.com" },
{ type: "block", path: "reddit.com" },
]);
Expand Down
35 changes: 0 additions & 35 deletions src/helpers/__tests__/normalize-url.test.ts

This file was deleted.

35 changes: 35 additions & 0 deletions src/helpers/__tests__/remove-protocol.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import removeProtocol from "../remove-protocol";

describe("removeProtocol()", () => {
it("removes https, http", () => {
expect(removeProtocol("https://example.com/")).toBe("example.com/");
expect(removeProtocol("http://example.com/")).toBe("example.com/");

expect(removeProtocol("https://www.example.com/")).toBe("www.example.com/");
expect(removeProtocol("http://www.example.com/")).toBe("www.example.com/");

expect(removeProtocol("https://dashboard.example.com/")).toBe("dashboard.example.com/");
expect(removeProtocol("http://dashboard.example.com/")).toBe("dashboard.example.com/");

expect(removeProtocol("https://www.dashboard.example.com/")).toBe("www.dashboard.example.com/");
expect(removeProtocol("http://www.dashboard.example.com/")).toBe("www.dashboard.example.com/");
});

it("keeps path unchanged", () => {
expect(removeProtocol("https://www.example.com/apple/projects/1?tab=analytics#charts")).toBe(
"www.example.com/apple/projects/1?tab=analytics#charts",
);

expect(removeProtocol("https://example.com/apple/projects/1?tab=analytics#charts")).toBe(
"example.com/apple/projects/1?tab=analytics#charts",
);

expect(removeProtocol("https://example.com/apple/projects/1")).toBe(
"example.com/apple/projects/1",
);

expect(removeProtocol("https://example.com/apple/projects/")).toBe(
"example.com/apple/projects/",
);
});
});
45 changes: 35 additions & 10 deletions src/helpers/find-rule.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,43 @@
import normalizeUrl from "./normalize-url";
import removeProtocol from "./remove-protocol";
import makeRules, { Rule } from "./make-rules";

const expandPath = (path: string) => {
const expanded = [path];
if (!["*.", "www."].find((prefix) => path.startsWith(prefix))) {
expanded.push(`www.${path}`);
}

[...expanded].forEach((path) => {
if (!path.includes("/")) {
expanded.push(`${path}/*`);
}
});

return expanded;
};

export default (url: string, blocked: string[]): Rule | undefined => {
const normalizedUrl = normalizeUrl(url);
const normalizedUrl = removeProtocol(url);
const rules = makeRules(blocked);

const foundRule = rules.find((rule) =>
normalizedUrl.match(new RegExp(
"^"
+ rule.path
.replace(/\?/g, ".") // user can type "?" to match any one character
.replace(/\*/g, ".*") // user can type "*" to match any zero or more characters
+ "$",
)));
const foundRule = rules.find(({ path }) => {
const patterns = expandPath(path)
.map((path) => path.replace(/[.+]/g, "\\$&")) // escape regex characters
.map((path) => (
"^"
+ path
.replace(/\?/g, ".") // user can type "?" to match any one character
.replace(/\*/g, ".*") // user can type "*" to match any zero or more characters
+ "$"
));

const found = patterns.some((pattern) => {
const matches = normalizedUrl.match(new RegExp(pattern));
return matches;
});

return found;
});

return foundRule;
};
6 changes: 3 additions & 3 deletions src/helpers/make-rules.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import normalizeUrl from "./normalize-url";
import removeProtocol from "./remove-protocol";

type RuleType = "allow" | "block"

Expand All @@ -10,11 +10,11 @@ export interface Rule {
export default (blocked: string[]): Rule[] => {
const allowList = blocked
.filter((item) => item.startsWith("!"))
.map((item) => normalizeUrl(item.substring(1)));
.map((item) => removeProtocol(item.substring(1)));

const blockList = blocked
.filter((item) => !item.startsWith("!"))
.map(normalizeUrl);
.map(removeProtocol);

return [
...allowList.map((path) => ({ type: "allow", path } as Rule)),
Expand Down
7 changes: 0 additions & 7 deletions src/helpers/normalize-url.ts

This file was deleted.

4 changes: 2 additions & 2 deletions src/helpers/recreate-context-menu.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import storage from "../storage";
import blockSite from "./block-site";
import normalizeUrl from "./normalize-url";
import removeProtocol from "./remove-protocol";

const createContextMenu = () => {
const parentId = chrome.contextMenus.create({
Expand All @@ -24,7 +24,7 @@ const createContextMenu = () => {

storage.get(["blocked"]).then(({ blocked }) => {
const url = info.pageUrl;
const normalizedUrl = normalizeUrl(url);
const normalizedUrl = removeProtocol(url);
const updatedBlocked = [...blocked, normalizedUrl];

storage.set({ blocked: updatedBlocked });
Expand Down
1 change: 1 addition & 0 deletions src/helpers/remove-protocol.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default (url: string): string => url.replace(/^http(s?):\/\//, "");

0 comments on commit ebe7c7a

Please sign in to comment.