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 StringPrototypeSlice, 14} = primordials; 15 16const { 17 ERR_SRI_PARSE, 18} = require('internal/errors').codes; 19const kWSP = '[\\x20\\x09]'; 20const kVCHAR = '[\\x21-\\x7E]'; 21const kHASH_ALGO = 'sha(?:256|384|512)'; 22// Base64 23const kHASH_VALUE = '[A-Za-z0-9+/]+[=]{0,2}'; 24const kHASH_EXPRESSION = `(${kHASH_ALGO})-(${kHASH_VALUE})`; 25// Ungrouped since unused 26const kOPTION_EXPRESSION = `(?:${kVCHAR}*)`; 27const kHASH_WITH_OPTIONS = `${kHASH_EXPRESSION}(?:[?](${kOPTION_EXPRESSION}))?`; 28const kSRIPattern = RegExp(`(${kWSP}*)(?:${kHASH_WITH_OPTIONS})`, 'g'); 29ObjectSeal(kSRIPattern); 30const kAllWSP = RegExp(`^${kWSP}*$`); 31ObjectSeal(kAllWSP); 32 33const BufferFrom = require('buffer').Buffer.from; 34 35// Returns {algorithm, value (in base64 string), options,}[] 36const parse = (str) => { 37 let prevIndex = 0; 38 let match; 39 const entries = []; 40 while ((match = RegExpPrototypeExec(kSRIPattern, str)) !== null) { 41 if (match.index !== prevIndex) { 42 throw new ERR_SRI_PARSE(str, str[prevIndex], prevIndex); 43 } 44 if (entries.length > 0 && match[1] === '') { 45 throw new ERR_SRI_PARSE(str, str[prevIndex], prevIndex); 46 } 47 48 // Avoid setters being fired 49 ObjectDefineProperty(entries, entries.length, { 50 __proto__: null, 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 (RegExpPrototypeExec(kAllWSP, StringPrototypeSlice(str, prevIndex)) === null) { 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