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