• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2// Utility to parse the value of
3// https://w3c.github.io/webappsec-subresource-integrity/#the-integrity-attribute
4
5const {
6  ObjectDefineProperty,
7  ObjectFreeze,
8  ObjectGetPrototypeOf,
9  ObjectSeal,
10  ObjectSetPrototypeOf,
11  RegExp,
12  RegExpPrototypeExec,
13  RegExpPrototypeTest,
14  StringPrototypeSlice,
15} = primordials;
16
17const {
18  ERR_SRI_PARSE
19} = require('internal/errors').codes;
20const kWSP = '[\\x20\\x09]';
21const kVCHAR = '[\\x21-\\x7E]';
22const kHASH_ALGO = 'sha(?:256|384|512)';
23// Base64
24const kHASH_VALUE = '[A-Za-z0-9+/]+[=]{0,2}';
25const kHASH_EXPRESSION = `(${kHASH_ALGO})-(${kHASH_VALUE})`;
26// Ungrouped since unused
27const kOPTION_EXPRESSION = `(?:${kVCHAR}*)`;
28const kHASH_WITH_OPTIONS = `${kHASH_EXPRESSION}(?:[?](${kOPTION_EXPRESSION}))?`;
29const kSRIPattern = RegExp(`(${kWSP}*)(?:${kHASH_WITH_OPTIONS})`, 'g');
30ObjectSeal(kSRIPattern);
31const kAllWSP = RegExp(`^${kWSP}*$`);
32ObjectSeal(kAllWSP);
33
34const BufferFrom = require('buffer').Buffer.from;
35const RealArrayPrototype = ObjectGetPrototypeOf([]);
36
37// Returns {algorithm, value (in base64 string), options,}[]
38const parse = (str) => {
39  let prevIndex = 0;
40  let match;
41  const entries = [];
42  while (match = RegExpPrototypeExec(kSRIPattern, str)) {
43    if (match.index !== prevIndex) {
44      throw new ERR_SRI_PARSE(str, str.charAt(prevIndex), prevIndex);
45    }
46    if (entries.length > 0 && match[1] === '') {
47      throw new ERR_SRI_PARSE(str, str.charAt(prevIndex), prevIndex);
48    }
49
50    // Avoid setters being fired
51    ObjectDefineProperty(entries, entries.length, {
52      enumerable: true,
53      configurable: true,
54      value: ObjectFreeze({
55        __proto__: null,
56        algorithm: match[2],
57        value: BufferFrom(match[3], 'base64'),
58        options: match[4] === undefined ? null : match[4],
59      })
60    });
61    prevIndex += match[0].length;
62  }
63
64  if (prevIndex !== str.length) {
65    if (!RegExpPrototypeTest(kAllWSP, StringPrototypeSlice(str, prevIndex))) {
66      throw new ERR_SRI_PARSE(str, str.charAt(prevIndex), prevIndex);
67    }
68  }
69  return ObjectSetPrototypeOf(entries, RealArrayPrototype);
70};
71
72module.exports = {
73  parse,
74};
75