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