All files / lib/internal/policy sri.js

100% Statements 73/73
92.31% Branches 12/13
100% Functions 1/1
100% Lines 73/73

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 7423x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 17x 17x 17x 17x 18x 1x 1x 18x 1x 1x 16x 16x 16x 16x 16x 16x 16x 16x 16x 18x 18x 18x 18x 18x 15x 17x 2x 2x 2x 2x 13x 23x 23x 23x 23x 23x  
'use strict';
// Utility to parse the value of
// https://w3c.github.io/webappsec-subresource-integrity/#the-integrity-attribute
 
const {
  ArrayPrototype,
  ObjectDefineProperty,
  ObjectFreeze,
  ObjectSeal,
  ObjectSetPrototypeOf,
  RegExp,
  RegExpPrototypeExec,
  RegExpPrototypeTest,
  StringPrototypeSlice,
} = primordials;
 
const {
  ERR_SRI_PARSE
} = require('internal/errors').codes;
const kWSP = '[\\x20\\x09]';
const kVCHAR = '[\\x21-\\x7E]';
const kHASH_ALGO = 'sha(?:256|384|512)';
// Base64
const kHASH_VALUE = '[A-Za-z0-9+/]+[=]{0,2}';
const kHASH_EXPRESSION = `(${kHASH_ALGO})-(${kHASH_VALUE})`;
// Ungrouped since unused
const kOPTION_EXPRESSION = `(?:${kVCHAR}*)`;
const kHASH_WITH_OPTIONS = `${kHASH_EXPRESSION}(?:[?](${kOPTION_EXPRESSION}))?`;
const kSRIPattern = RegExp(`(${kWSP}*)(?:${kHASH_WITH_OPTIONS})`, 'g');
ObjectSeal(kSRIPattern);
const kAllWSP = RegExp(`^${kWSP}*$`);
ObjectSeal(kAllWSP);
 
const BufferFrom = require('buffer').Buffer.from;
 
// Returns {algorithm, value (in base64 string), options,}[]
const parse = (str) => {
  let prevIndex = 0;
  let match;
  const entries = [];
  while (match = RegExpPrototypeExec(kSRIPattern, str)) {
    if (match.index !== prevIndex) {
      throw new ERR_SRI_PARSE(str, str[prevIndex], prevIndex);
    }
    if (entries.length > 0 && match[1] === '') {
      throw new ERR_SRI_PARSE(str, str[prevIndex], prevIndex);
    }
 
    // Avoid setters being fired
    ObjectDefineProperty(entries, entries.length, {
      enumerable: true,
      configurable: true,
      value: ObjectFreeze({
        __proto__: null,
        algorithm: match[2],
        value: BufferFrom(match[3], 'base64'),
        options: match[4] === undefined ? null : match[4],
      })
    });
    prevIndex += match[0].length;
  }
 
  if (prevIndex !== str.length) {
    if (!RegExpPrototypeTest(kAllWSP, StringPrototypeSlice(str, prevIndex))) {
      throw new ERR_SRI_PARSE(str, str[prevIndex], prevIndex);
    }
  }
  return ObjectSetPrototypeOf(entries, ArrayPrototype);
};
 
module.exports = {
  parse,
};