All files scope.ts

100% Statements 48/48
100% Branches 16/16
100% Functions 14/14
100% Lines 34/34

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73    2x       4x 3x         3x 10x               7x 7x     44x 6x 21x   21x 11x 11x     10x 10x   10x   6x   6x         6x 6x   19x 11x 5x 8x 8x   5x 8x   5x         2x 3x   2x 9x   2x   2x  
import { AuthScope, StringStringMap } from './interfaces';
 
export default class Scope implements AuthScope {
  private SCOPE: StringStringMap;
  private REVERSE_SCOPE: StringStringMap;
 
  constructor(scope: StringStringMap = {}) {
    this.SCOPE = {
      read: 'r',
      write: 'w',
      ...scope
    };
    this.REVERSE_SCOPE = Object.entries(this.SCOPE).reduce(
      (obj, [k, v]) => ({ ...obj, [v]: k }),
      {}
    );
  }
  /**
   * Returns a scope in the format 'a:r:w' using a set of rules like
   * ['admin:read', 'admin:write']
   */
  public create(scope: string[]): string {
    if (!scope.length) return '';
 
    let lastName: string;
    const shortPerm = (perm: string) => this.SCOPE[perm] || perm;
    const shortRole = (newScope: string[], r: string) => {
      const role = r.split(':').map(shortPerm);
 
      if (lastName === role[0]) {
        newScope[newScope.length - 1] += `:${role.slice(1).join(':')}`;
        return newScope;
      }
 
      lastName = role[0];
      newScope.push(role.join(':'));
 
      return newScope;
    };
    const scopeStr = scope.reduce(shortRole, []).join('|');
 
    return scopeStr;
  }
  /**
   * Returns a scope string as an array of rules
   */
  public parse(scopeStr: string): string[] {
    if (!scopeStr) return [];
 
    const longPerm = (perm: string) => this.REVERSE_SCOPE[perm] || perm;
    const joinPerm = (name: string) => (perm: string) => name + ':' + perm;
    const splitRole = (role: string) => {
      const [name, ...perms] = role.split(':').map(longPerm);
      return perms.map(joinPerm(name));
    };
    const pushRoles = (roles: string[], role: string) =>
      roles.concat(splitRole(role));
 
    return scopeStr.split('|').reduce(pushRoles, []);
  }
  /**
   * Checks whether or not a perm is included in a parsed scope
   */
  public has(scope: string[], perm: string | string[]) {
    if (!scope.length) return false;
 
    const perms = Array.isArray(perm) ? perm : [perm];
    const withPerm = (p: string) => perms.indexOf(p) !== -1;
 
    return !!scope.find(withPerm);
  }
}