aboutsummaryrefslogtreecommitdiff
path: root/src/shared/settings/Blacklist.ts
diff options
context:
space:
mode:
authorShin'ya UEOKA <ueokande@i-beam.org>2019-10-05 08:52:49 +0000
committerShin'ya UEOKA <ueokande@i-beam.org>2019-10-07 13:01:31 +0000
commit9ff80fcac3600401c9fed053cc8422f89c404940 (patch)
tree49950c7c2d997438f9e30ca83d1aa604e8b424af /src/shared/settings/Blacklist.ts
parent8eddcc1785a85bbe74be254d1055ebe5125dad10 (diff)
Add partial blacklist item
Diffstat (limited to 'src/shared/settings/Blacklist.ts')
-rw-r--r--src/shared/settings/Blacklist.ts116
1 files changed, 97 insertions, 19 deletions
diff --git a/src/shared/settings/Blacklist.ts b/src/shared/settings/Blacklist.ts
index a95b606..5648611 100644
--- a/src/shared/settings/Blacklist.ts
+++ b/src/shared/settings/Blacklist.ts
@@ -1,39 +1,117 @@
-export type BlacklistJSON = string[];
+export type BlacklistItemJSON = string | {
+ url: string,
+ keys: string[],
+};
+
+export type BlacklistJSON = BlacklistItemJSON[];
-const fromWildcard = (pattern: string): RegExp => {
+const regexFromWildcard = (pattern: string): RegExp => {
let regexStr = '^' + pattern.replace(/\*/g, '.*') + '$';
return new RegExp(regexStr);
};
+const isArrayOfString = (raw: any): boolean => {
+ if (!Array.isArray(raw)) {
+ return false;
+ }
+ for (let x of Array.from(raw)) {
+ if (typeof x !== 'string') {
+ return false;
+ }
+ }
+ return true;
+};
+
+export class BlacklistItem {
+ public readonly pattern: string;
+
+ private regex: RegExp;
+
+ public readonly partial: boolean;
+
+ public readonly keys: string[];
+
+ private constructor(
+ pattern: string,
+ partial: boolean,
+ keys: string[]
+ ) {
+ this.pattern = pattern;
+ this.regex = regexFromWildcard(pattern);
+ this.partial = partial;
+ this.keys = keys;
+ }
+
+ static fromJSON(raw: any): BlacklistItem {
+ if (typeof raw === 'string') {
+ return new BlacklistItem(raw, false, []);
+ } else if (typeof raw === 'object' && raw !== null) {
+ if (!('url' in raw)) {
+ throw new TypeError(
+ `missing field "url" of blacklist item: ${JSON.stringify(raw)}`);
+ }
+ if (typeof raw.url !== 'string') {
+ throw new TypeError(
+ `invalid field "url" of blacklist item: ${JSON.stringify(raw)}`);
+ }
+ if (!('keys' in raw)) {
+ throw new TypeError(
+ `missing field "keys" of blacklist item: ${JSON.stringify(raw)}`);
+ }
+ if (!isArrayOfString(raw.keys)) {
+ throw new TypeError(
+ `invalid field "keys" of blacklist item: ${JSON.stringify(raw)}`);
+ }
+ return new BlacklistItem(raw.url as string, true, raw.keys as string[]);
+ }
+ throw new TypeError(
+ `invalid format of blacklist item: ${JSON.stringify(raw)}`);
+ }
+
+ toJSON(): BlacklistItemJSON {
+ if (!this.partial) {
+ return this.pattern;
+ }
+ return { url: this.pattern, keys: this.keys };
+ }
+
+ matches(url: URL): boolean {
+ return this.pattern.includes('/')
+ ? this.regex.test(url.host + url.pathname)
+ : this.regex.test(url.host);
+ }
+
+ includeKey(url: URL, keys: string): boolean {
+ if (!this.matches(url)) {
+ return false;
+ }
+ return !this.partial || this.keys.includes(keys);
+ }
+}
+
export default class Blacklist {
constructor(
- private blacklist: string[],
+ private blacklist: BlacklistItem[],
) {
}
static fromJSON(json: any): Blacklist {
if (!Array.isArray(json)) {
- throw new TypeError(`"blacklist" is not an array of string`);
- }
- for (let x of json) {
- if (typeof x !== 'string') {
- throw new TypeError(`"blacklist" is not an array of string`);
- }
+ throw new TypeError('blacklist is not an array: ' + JSON.stringify(json));
}
- return new Blacklist(json);
+ let items = Array.from(json).map(item => BlacklistItem.fromJSON(item));
+ return new Blacklist(items);
}
toJSON(): BlacklistJSON {
- return this.blacklist;
+ return this.blacklist.map(item => item.toJSON());
}
- includes(url: string): boolean {
- let u = new URL(url);
- return this.blacklist.some((item) => {
- if (!item.includes('/')) {
- return fromWildcard(item).test(u.host);
- }
- return fromWildcard(item).test(u.host + u.pathname);
- });
+ includesEntireBlacklist(url: URL): boolean {
+ return this.blacklist.some(item => !item.partial && item.matches(url));
+ }
+
+ includeKey(url: URL, key: string) {
+ return this.blacklist.some(item => item.includeKey(url, key));
}
}