• 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  ArrayPrototype,
7  ObjectDefineProperty,
8  ObjectFreeze,
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;
35
36// Returns {algorithm, value (in base64 string), options,}[]
37const parse = (str) => {
38  let prevIndex = 0;
39  let match;
40  const entries = [];
41  while (match = RegExpPrototypeExec(kSRIPattern, str)) {
42    if (match.index !== prevIndex) {
43      throw new ERR_SRI_PARSE(str, str[prevIndex], prevIndex);
44    }
45    if (entries.length > 0 && match[1] === '') {
46      throw new ERR_SRI_PARSE(str, str[prevIndex], prevIndex);
47    }
48
49    // Avoid setters being fired
50    ObjectDefineProperty(entries, entries.length, {
51      enumerable: true,
52      configurable: true,
53      value: ObjectFreeze({
54        __proto__: null,
55        algorithm: match[2],
56        value: BufferFrom(match[3], 'base64'),
57        options: match[4] === undefined ? null : match[4],
58      })
59    });
60    prevIndex += match[0].length;
61  }
62
63  if (prevIndex !== str.length) {
64    if (!RegExpPrototypeTest(kAllWSP, StringPrototypeSlice(str, prevIndex))) {
65      throw new ERR_SRI_PARSE(str, str[prevIndex], prevIndex);
66    }
67  }
68  return ObjectSetPrototypeOf(entries, ArrayPrototype);
69};
70
71module.exports = {
72  parse,
73};
74