diff options
| author | Shin'ya Ueoka <ueokande@i-beam.org> | 2019-10-09 11:50:52 +0000 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-10-09 11:50:52 +0000 | 
| commit | 18c72bf15c6bc7e4c88dd06d38ff861f29d66b1b (patch) | |
| tree | f46720349e17c57db7bbfc55241b12c4410f2773 /src/shared/settings | |
| parent | 8eddcc1785a85bbe74be254d1055ebe5125dad10 (diff) | |
| parent | 68f6211aac4177f3a70a40031dabbd1b61840071 (diff) | |
Merge pull request #655 from ueokande/partial-blacklist
Partial blacklist
Diffstat (limited to 'src/shared/settings')
| -rw-r--r-- | src/shared/settings/Blacklist.ts | 124 | ||||
| -rw-r--r-- | src/shared/settings/KeySequence.ts | 2 | 
2 files changed, 106 insertions, 20 deletions
| diff --git a/src/shared/settings/Blacklist.ts b/src/shared/settings/Blacklist.ts index a95b606..0cfbd71 100644 --- a/src/shared/settings/Blacklist.ts +++ b/src/shared/settings/Blacklist.ts @@ -1,39 +1,125 @@ -export type BlacklistJSON = string[]; +import Key from './Key'; -const fromWildcard = (pattern: string): RegExp => { +export type BlacklistItemJSON = string | { +  url: string, +  keys: string[], +}; + +export type BlacklistJSON = BlacklistItemJSON[]; + +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 readonly keyEntities: Key[]; + +  constructor( +    pattern: string, +    partial: boolean, +    keys: string[] +  ) { +    this.pattern = pattern; +    this.regex = regexFromWildcard(pattern); +    this.partial = partial; +    this.keys = keys; +    this.keyEntities = this.keys.map(Key.fromMapKey); +  } + +  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, key: Key): boolean { +    if (!this.matches(url)) { +      return false; +    } +    if (!this.partial) { +      return true; +    } +    return this.keyEntities.some(k => k.equals(key)); +  } +} +  export default class Blacklist {    constructor( -    private blacklist: string[], +    public readonly items: BlacklistItem[],    ) {    }    static fromJSON(json: any): Blacklist {      if (!Array.isArray(json)) { -      throw new TypeError(`"blacklist" is not an array of string`); +      throw new TypeError('blacklist is not an array: ' + JSON.stringify(json));      } -    for (let x of json) { -      if (typeof x !== 'string') { -        throw new TypeError(`"blacklist" is not an array of string`); -      } -    } -    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.items.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.items.some(item => !item.partial && item.matches(url)); +  } + +  includeKey(url: URL, key: Key) { +    return this.items.some(item => item.includeKey(url, key));    }  } diff --git a/src/shared/settings/KeySequence.ts b/src/shared/settings/KeySequence.ts index 4955583..abae61a 100644 --- a/src/shared/settings/KeySequence.ts +++ b/src/shared/settings/KeySequence.ts @@ -1,4 +1,4 @@ -import Key from '../../shared/settings/Key'; +import Key from './Key';  export default class KeySequence {    constructor( | 
