feat(plugin): add clearURLs (#47)
This commit is contained in:
134
src/plugins/clearURLs/index.ts
Normal file
134
src/plugins/clearURLs/index.ts
Normal file
@ -0,0 +1,134 @@
|
||||
import { defaultRules } from "./defaultRules";
|
||||
import {
|
||||
addPreSendListener,
|
||||
addPreEditListener,
|
||||
MessageObject,
|
||||
removePreSendListener,
|
||||
removePreEditListener,
|
||||
} from "../../api/MessageEvents";
|
||||
import definePlugin from "../../utils/types";
|
||||
|
||||
// From lodash
|
||||
const reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
|
||||
const reHasRegExpChar = RegExp(reRegExpChar.source);
|
||||
|
||||
export default definePlugin({
|
||||
name: "clearURLs",
|
||||
description: "Removes tracking garbage from URLs",
|
||||
authors: [
|
||||
{
|
||||
name: "adryd",
|
||||
id: 0n,
|
||||
},
|
||||
],
|
||||
dependencies: ["MessageEventsAPI"],
|
||||
|
||||
escapeRegExp(str: string) {
|
||||
return (str && reHasRegExpChar.test(str))
|
||||
? str.replace(reRegExpChar, "\\$&")
|
||||
: (str || "");
|
||||
},
|
||||
|
||||
createRules() {
|
||||
// Can be extended upon once user configs are available
|
||||
// Eg. (useDefaultRules: boolean, customRules: Array[string])
|
||||
const rules = defaultRules;
|
||||
|
||||
this.universalRules = new Set();
|
||||
this.rulesByHost = new Map();
|
||||
this.hostRules = new Map();
|
||||
|
||||
for (const rule of rules) {
|
||||
const splitRule = rule.split("@");
|
||||
const paramRule = new RegExp(
|
||||
"^" +
|
||||
this.escapeRegExp(splitRule[0]).replace(/\\\*/, ".+?") +
|
||||
"$"
|
||||
);
|
||||
|
||||
if (!splitRule[1]) {
|
||||
this.universalRules.add(paramRule);
|
||||
continue;
|
||||
}
|
||||
const hostRule = new RegExp(
|
||||
"^(www\\.)?" +
|
||||
this.escapeRegExp(splitRule[1])
|
||||
.replace(/\\\./, "\\.")
|
||||
.replace(/^\\\*\\\./, "(.+?\\.)?")
|
||||
.replace(/\\\*/, ".+?") +
|
||||
"$"
|
||||
);
|
||||
const hostRuleIndex = hostRule.toString();
|
||||
|
||||
this.hostRules.set(hostRuleIndex, hostRule);
|
||||
if (this.rulesByHost.get(hostRuleIndex) == null) {
|
||||
this.rulesByHost.set(hostRuleIndex, new Set());
|
||||
}
|
||||
this.rulesByHost.get(hostRuleIndex).add(paramRule);
|
||||
}
|
||||
},
|
||||
|
||||
removeParam(rule: string | RegExp, param: string, parent: URLSearchParams) {
|
||||
if (param === rule || rule instanceof RegExp && rule.test(param)) {
|
||||
parent.delete(param);
|
||||
}
|
||||
},
|
||||
|
||||
replacer(match: string) {
|
||||
// Parse URL without throwing errors
|
||||
try {
|
||||
var url = new URL(match);
|
||||
} catch (error) {
|
||||
// Don't modify anything if we can't parse the URL
|
||||
return match;
|
||||
}
|
||||
|
||||
// Cheap way to check if there are any search params
|
||||
if (url.searchParams.entries().next().done) {
|
||||
// If there are none, we don't need to modify anything
|
||||
return match;
|
||||
}
|
||||
|
||||
// Check all universal rules
|
||||
this.universalRules.forEach((rule) => {
|
||||
url.searchParams.forEach((_value, param, parent) => {
|
||||
this.removeParam(rule, param, parent);
|
||||
});
|
||||
});
|
||||
|
||||
// Check rules for each hosts that match
|
||||
this.hostRules.forEach((regex, hostRuleName) => {
|
||||
if (!regex.test(url.hostname)) return;
|
||||
this.rulesByHost.get(hostRuleName).forEach((rule) => {
|
||||
url.searchParams.forEach((_value, param, parent) => {
|
||||
this.removeParam(rule, param, parent);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return url.toString();
|
||||
},
|
||||
|
||||
onSend(msg: MessageObject) {
|
||||
// Only run on messages that contain URLs
|
||||
if (msg.content.match(/http(s)?:\/\//)) {
|
||||
msg.content = msg.content.replace(
|
||||
/(https?:\/\/[^\s<]+[^<.,:;"'>)|\]\s])/g,
|
||||
(match) => this.replacer(match)
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
start() {
|
||||
this.createRules();
|
||||
this.preSend = addPreSendListener((_, msg) => this.onSend(msg));
|
||||
this.preEdit = addPreEditListener((_cid, _mid, msg) =>
|
||||
this.onSend(msg)
|
||||
);
|
||||
},
|
||||
|
||||
stop() {
|
||||
removePreSendListener(this.preSend);
|
||||
removePreEditListener(this.preEdit);
|
||||
},
|
||||
});
|
Reference in New Issue
Block a user