diff --git a/README.md b/README.md index 14e91bc..d5dcbbd 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ Integrity](https://w3c.github.io/webappsec/specs/subresourceintegrity/) hashes. * [`Integrity#pickAlgorithm`](#integrity-pick-algorithm) * [`IntegrityMetadata#hexDigest`](#integrity-metadata-hex-digest) * Integrity Generation + * [`fromHex`](#from-hex) * [`fromData`](#from-data) * [`fromStream`](#from-stream) * Integrity Verification @@ -227,6 +228,33 @@ to a hex representation of the base64 data. ssri.parse('sha1-deadbeef', {single: true}).hexDigest() // '75e69d6de79f' ``` +#### `> ssri.fromHex(hexDigest, algorithm, [opts]) -> Integrity` + +Creates an `Integrity` object with a single entry, based on a hex-formatted +hash. This is a utility function to help convert existing shasums to the +Integrity format, and is roughly equivalent to something like: + +```javascript +algorithm + '-' + Buffer.from(hexDigest, 'hex').toString('base64') +``` + +`opts.options` may optionally be passed in: it must be an array of option +strings that will be added to all generated integrity metadata generated by +`fromData`. This is a loosely-specified feature of SRIs, and currently has no +specified semantics besides being `?`-separated. Use at your own risk, and +probably avoid if your integrity strings are meant to be used with browsers. + +If `opts.strict` is true, the integrity object will be created using strict +parsing rules. See [`ssri.parse`](#parse). + +If `opts.single` is true, a single `IntegrityMetadata` object will be returned. + +##### Example + +```javascript +ssri.fromHex('75e69d6de79f', 'sha1').toString() // 'sha1-deadbeef' +``` + #### `> ssri.fromData(data, [opts]) -> Integrity` Creates an `Integrity` object from either string or `Buffer` data, calculating diff --git a/index.js b/index.js index 9a660ef..038b639 100644 --- a/index.js +++ b/index.js @@ -31,11 +31,7 @@ class IntegrityMetadata { this.options = rawOpts ? rawOpts.slice(1).split('?') : [] } hexDigest () { - return this.digest && ( - Buffer.from - ? Buffer.from(this.digest, 'base64') - : new Buffer(this.digest, 'base64') - ).toString('hex') + return this.digest && bufFrom(this.digest, 'base64').toString('hex') } toString (opts) { if (opts && opts.strict) { @@ -136,6 +132,18 @@ function stringify (obj, opts) { } } +module.exports.fromHex = fromHex +function fromHex (hexDigest, algorithm, opts) { + const optString = (opts && opts.options && opts.options.length) + ? `?${opts.options.join('?')}` + : '' + return parse( + `${algorithm}-${ + bufFrom(hexDigest, 'hex').toString('base64') + }${optString}`, opts + ) +} + module.exports.fromData = fromData function fromData (data, opts) { opts = opts || {} @@ -254,3 +262,7 @@ function getPrioritizedHash (algo1, algo2) { ? algo1 : algo2 } + +function bufFrom (data, enc) { + return Buffer.from ? Buffer.from(data, enc) : new Buffer(data, enc) +} diff --git a/test/from.js b/test/from.js index 5997617..d6da52d 100644 --- a/test/from.js +++ b/test/from.js @@ -16,6 +16,20 @@ function fileStream () { return fs.createReadStream(__filename) } +test('fromHex', t => { + t.equal( + ssri.fromHex('deadbeef', 'sha1').toString(), + `sha1-3q2+7w==`, + 'created an Integrity object from a given hex + sha' + ) + t.equal( + ssri.fromHex('deadbeef', 'sha512', {options: ['a', 'b', 'c']}).toString(), + `sha512-3q2+7w==?a?b?c`, + 'options added to entry' + ) + t.done() +}) + test('fromData', t => { t.equal( ssri.fromData(TEST_DATA).toString(),