Skip to content

Commit

Permalink
fix(opts): use figgy-pudding to specify consumed opts
Browse files Browse the repository at this point in the history
  • Loading branch information
zkat committed Aug 27, 2018
1 parent 97b032d commit cf86553
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 21 deletions.
58 changes: 38 additions & 20 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict'

const crypto = require('crypto')
const figgyPudding = require('figgy-pudding')
const Transform = require('stream').Transform

const SPEC_ALGORITHMS = ['sha256', 'sha384', 'sha512']
Expand All @@ -10,10 +11,24 @@ const SRI_REGEX = /^([^-]+)-([^?]+)([?\S*]*)$/
const STRICT_SRI_REGEX = /^([^-]+)-([A-Za-z0-9+/=]{44,88})(\?[\x21-\x7E]*)*$/
const VCHAR_REGEX = /^[\x21-\x7E]+$/

const SsriOpts = figgyPudding({
algorithms: {default: ['sha512']},
error: {default: false},
integrity: {},
options: {default: []},
pickAlgorithm: {default: () => getPrioritizedHash},
Promise: {default: () => Promise},
sep: {default: ' '},
single: {default: false},
size: {},
strict: {default: false}
})

class Hash {
get isHash () { return true }
constructor (hash, opts) {
const strict = !!(opts && opts.strict)
opts = SsriOpts(opts)
const strict = !!opts.strict
this.source = hash.trim()
// 3.1. Integrity metadata (called "Hash" by ssri)
// https://w3c.github.io/webappsec-subresource-integrity/#integrity-metadata-description
Expand All @@ -37,7 +52,8 @@ class Hash {
return this.toString()
}
toString (opts) {
if (opts && opts.strict) {
opts = SsriOpts(opts)
if (opts.strict) {
// Strict mode enforces the standard as close to the foot of the
// letter as it can.
if (!(
Expand Down Expand Up @@ -70,7 +86,7 @@ class Integrity {
return this.toString()
}
toString (opts) {
opts = opts || {}
opts = SsriOpts(opts)
let sep = opts.sep || ' '
if (opts.strict) {
// Entries must be separated by whitespace, according to spec.
Expand All @@ -83,6 +99,7 @@ class Integrity {
}).filter(x => x.length).join(sep)
}
concat (integrity, opts) {
opts = SsriOpts(opts)
const other = typeof integrity === 'string'
? integrity
: stringify(integrity, opts)
Expand All @@ -92,6 +109,7 @@ class Integrity {
return parse(this, {single: true}).hexDigest()
}
match (integrity, opts) {
opts = SsriOpts(opts)
const other = parse(integrity, opts)
const algo = other.pickAlgorithm(opts)
return (
Expand All @@ -105,7 +123,8 @@ class Integrity {
) || false
}
pickAlgorithm (opts) {
const pickAlgorithm = (opts && opts.pickAlgorithm) || getPrioritizedHash
opts = SsriOpts(opts)
const pickAlgorithm = opts.pickAlgorithm
const keys = Object.keys(this)
if (!keys.length) {
throw new Error(`No algorithms available for ${
Expand All @@ -120,7 +139,7 @@ class Integrity {

module.exports.parse = parse
function parse (sri, opts) {
opts = opts || {}
opts = SsriOpts(opts)
if (typeof sri === 'string') {
return _parse(sri, opts)
} else if (sri.algorithm && sri.digest) {
Expand Down Expand Up @@ -151,6 +170,7 @@ function _parse (integrity, opts) {

module.exports.stringify = stringify
function stringify (obj, opts) {
opts = SsriOpts(opts)
if (obj.algorithm && obj.digest) {
return Hash.prototype.toString.call(obj, opts)
} else if (typeof obj === 'string') {
Expand All @@ -162,7 +182,8 @@ function stringify (obj, opts) {

module.exports.fromHex = fromHex
function fromHex (hexDigest, algorithm, opts) {
const optString = (opts && opts.options && opts.options.length)
opts = SsriOpts(opts)
const optString = opts.options && opts.options.length
? `?${opts.options.join('?')}`
: ''
return parse(
Expand All @@ -174,8 +195,8 @@ function fromHex (hexDigest, algorithm, opts) {

module.exports.fromData = fromData
function fromData (data, opts) {
opts = opts || {}
const algorithms = opts.algorithms || ['sha512']
opts = SsriOpts(opts)
const algorithms = opts.algorithms
const optString = opts.options && opts.options.length
? `?${opts.options.join('?')}`
: ''
Expand All @@ -196,7 +217,7 @@ function fromData (data, opts) {

module.exports.fromStream = fromStream
function fromStream (stream, opts) {
opts = opts || {}
opts = SsriOpts(opts)
const P = opts.Promise || Promise
const istream = integrityStream(opts)
return new P((resolve, reject) => {
Expand All @@ -212,7 +233,7 @@ function fromStream (stream, opts) {

module.exports.checkData = checkData
function checkData (data, sri, opts) {
opts = opts || {}
opts = SsriOpts(opts)
sri = parse(sri, opts)
if (!Object.keys(sri).length) {
if (opts.error) {
Expand Down Expand Up @@ -251,9 +272,9 @@ function checkData (data, sri, opts) {

module.exports.checkStream = checkStream
function checkStream (stream, sri, opts) {
opts = opts || {}
opts = SsriOpts(opts)
const P = opts.Promise || Promise
const checker = integrityStream(Object.assign({}, opts, {
const checker = integrityStream(opts.concat({
integrity: sri
}))
return new P((resolve, reject) => {
Expand All @@ -269,18 +290,15 @@ function checkStream (stream, sri, opts) {

module.exports.integrityStream = integrityStream
function integrityStream (opts) {
opts = opts || {}
opts = SsriOpts(opts)
// For verification
const sri = opts.integrity && parse(opts.integrity, opts)
const goodSri = sri && Object.keys(sri).length
const algorithm = goodSri && sri.pickAlgorithm(opts)
const digests = goodSri && sri[algorithm]
// Calculating stream
const algorithms = Array.from(
new Set(
(opts.algorithms || ['sha512'])
.concat(algorithm ? [algorithm] : [])
)
new Set(opts.algorithms.concat(algorithm ? [algorithm] : []))
)
const hashes = algorithms.map(crypto.createHash)
let streamSize = 0
Expand Down Expand Up @@ -325,9 +343,9 @@ function integrityStream (opts) {

module.exports.create = createIntegrity
function createIntegrity (opts) {
opts = opts || {}
const algorithms = opts.algorithms || ['sha512']
const optString = opts.options && opts.options.length
opts = SsriOpts(opts)
const algorithms = opts.algorithms
const optString = opts.options.length
? `?${opts.options.join('?')}`
: ''

Expand Down
5 changes: 5 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@
"twitter": "maybekatz"
},
"license": "ISC",
"dependencies": {},
"dependencies": {
"figgy-pudding": "^3.5.1"
},
"devDependencies": {
"nyc": "^11.4.1",
"standard": "^10.0.3",
Expand Down

0 comments on commit cf86553

Please sign in to comment.