Skip to content

Commit

Permalink
docs: bring README up to date with latest API
Browse files Browse the repository at this point in the history
  • Loading branch information
zkat committed Mar 24, 2017
1 parent f72e658 commit 2dc11d1
Showing 1 changed file with 256 additions and 4 deletions.
260 changes: 256 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ Integrity](https://w3c.github.io/webappsec/specs/subresourceintegrity/) hashes.
* [API](#api)
* Parsing & Serializing
* [`parse`](#parse)
* [`unparse`](#unparse)
* [`Integrity#concat`](#integrity-concat)
* [`Integrity#toString`](#integrity-to-string)
* [`serialize`](#serialize)
* Integrity Generation
* [`fromData`](#from-data)
* [`fromStream`](#from-stream)
Expand All @@ -35,7 +37,7 @@ const integrity = 'sha512-9KhgCRIx/AmzC8xqYJTZRrnO8OW2Pxyl2DIMZSBOr0oDvtEFyht3xp
// Parsing and serializing
const parsed = ssri.parse(integrity)
parsed.toString() // === integrity
ssri.unparse(parsed) // === integrity (works on non-Integrity objects)
ssri.serialize(parsed) // === integrity (works on non-Integrity objects)

// Async stream functions
ssri.checkStream(fs.createReadStream('./my-file'), parsed).then(...)
Expand All @@ -53,11 +55,261 @@ ssri.checkData(fs.readFileSync('./my-file'), parsed) // => true

* Parses and unparses SRI strings.
* Generates SRI strings from direct data or Streams.
* Optional use of reserved option expression syntax.
* Optional use of reserved `option-expression` syntax.
* Multiple entries for the same algorithm.
* Object-based integrity string manipulation.

### Contributing

The ssri team enthusiastically welcomes contributions and project participation! There's a bunch of things you can do if you want to contribute! The [Contributor Guide](CONTRIBUTING.md) has all the information you need for everything from reporting bugs to contributing entire new features. Please don't hesitate to jump in if you'd like to, or even ask us questions if something isn't clear.
The ssri team enthusiastically welcomes contributions and project participation!
There's a bunch of things you can do if you want to contribute! The [Contributor
Guide](CONTRIBUTING.md) has all the information you need for everything from
reporting bugs to contributing entire new features. Please don't hesitate to
jump in if you'd like to, or even ask us questions if something isn't clear.

### API

#### <a name="parse"></a> `> ssri.parse(integrityString) -> Integrity`

Parses an `integrity` string into an `Integrity` data structure. The resulting
object has this shape:

```javascript
{
'sha1': [{algorithm: 'sha1', digest: 'deadbeef', options: []}],
'sha512': [
{algorithm: 'sha512', digest: 'c0ffee', options: []},
{algorithm: 'sha512', digest: 'bad1dea', options: ['foo']}
],
}
```

##### Example

```javascript
ssri.parse('sha512-9KhgCRIx/AmzC8xqYJTZRrnO8OW2Pxyl2DIMZSBOr0oDvtEFyht3xpp71j/r/pAe1DM+JI/A+line3jUBgzQ7A==?foo') // -> Integrity
```

#### <a name="integrity-concat"></a> `> Integrity#concat(otherIntegrity) -> Integrity`

Concatenates an `Integrity` object with another IntegrityLike, or a string
representing integrity metadata.

This is functionally equivalent to concatenating the string format of both
integrity arguments, and calling [`ssri.parse`](#ssri-parse) on the new string.

##### Example

```javascript
// This will combine the integrity checks for two different versions of
// your index.js file so you can use a single integrity string and serve
// either of these to clients, from a single `<script>` tag.
const desktopIntegrity = ssri.fromData(fs.readFileSync('./index.desktop.js'))
const mobileIntegrity = ssri.fromData(fs.readFileSync('./index.mobile.js'))

// Note that browsers (and ssri) will succeed as long as ONE of the entries
// for the *prioritized* algorithm succeeds. That is, in order for this fallback
// to work, both desktop and mobile *must* use the same `algorithm` values.
desktopIntegrity.concat(mobileIntegrity)
```

#### <a name="integrity-to-string"></a> `> Integrity#toString([sep=' ']) -> String`

Returns the string representation of an `Integrity` object. All metadata entries
will be concatenated in the string by `sep`.

If you want to serialize an object that didn't from from an `ssri` function,
use [`ssri.serialize()`](#serialize).

##### Example

```javascript
const integrity = 'sha512-9KhgCRIx/AmzC8xqYJTZRrnO8OW2Pxyl2DIMZSBOr0oDvtEFyht3xpp71j/r/pAe1DM+JI/A+line3jUBgzQ7A==?foo'

ssri.parse(integrity).toString() === integrity
```

#### <a name="serialize"></a> `> ssri.serialize(integrityObj, [sep=' ']) -> String`

This function is identical to [`Integrity#toString()`](#integrity-to-string),
except it can be used on _any_ object resembling the shape of either an
`Integrity` or an `IntegrityMedatada` object.

If `IntegrityLike` has both `.algorithm` and `.digest` properties, it will be
serialized as a single integrity entry. That is, `<algorithm>-<digest>`, along
with `?<options.join('?')>` if the object has an `options` property.

Otherwise, the `IntegrityLike` will be treated as a full `Integrity` object,
where every key on the object will be interpreted as an algorithm, and each
value should be an array of metadata objects (with `algorithm` and `digest`
properties) corresponding to that key.

The `sep` option defines the string to use when joining multiple entries
together. To be spec-compliant, this _must_ be whitespace. The default is a
single space (`' '`).

##### Example

```javascript
// IntegrityMetadata-like: only a single entry.
ssri.serialize({
algorithm: 'sha512',
digest:'9KhgCRIx/AmzC8xqYJTZRrnO8OW2Pxyl2DIMZSBOr0oDvtEFyht3xpp71j/r/pAe1DM+JI/A+line3jUBgzQ7A==',
options: ['foo']
})
// ->
// 'sha512-9KhgCRIx/AmzC8xqYJTZRrnO8OW2Pxyl2DIMZSBOr0oDvtEFyht3xpp71j/r/pAe1DM+JI/A+line3jUBgzQ7A==?foo'

// Integrity-like: full multi-entry syntax. Similar to output of `ssri.parse`
ssri.serialize({
'sha512': [
{
algorithm: 'sha512',
digest:'9KhgCRIx/AmzC8xqYJTZRrnO8OW2Pxyl2DIMZSBOr0oDvtEFyht3xpp71j/r/pAe1DM+JI/A+line3jUBgzQ7A==',
options: ['foo']
}
]
})
// ->
// 'sha512-9KhgCRIx/AmzC8xqYJTZRrnO8OW2Pxyl2DIMZSBOr0oDvtEFyht3xpp71j/r/pAe1DM+JI/A+line3jUBgzQ7A==?foo'
```

#### <a name="from-data"></a> `> ssri.fromData(data, [opts]) -> Integrity`

Creates an `Integrity` object from either string or `Buffer` data, calculating
all the requested hashes and adding any specified options to the object.

`opts.algorithms` determines which algorithms to generate metadata for. All
results will be included in a single `Integrity` object. The default value for
`opts.algorithms` is `['sha512']`. All algorithm strings must be hashes listed
in `crypto.getHashes()` for the host Node.js platform.

`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.

##### Example

```javascript
const integrityObj = ssri.fromData('foobarbaz', {
algorithms: ['sha256', 'sha384', 'sha512']
})
integrity.toString('\n')
// ->
// sha256-l981iLWj8kurw4UbNy8Lpxqdzd7UOxS50Glhv8FwfZ0=
// sha384-irnCxQ0CfQhYGlVAUdwTPC9bF3+YWLxlaDGM4xbYminxpbXEq+D+2GCEBTxcjES9
// sha512-yzd8ELD1piyANiWnmdnpCL5F52f10UfUdEkHywVZeqTt0ymgrxR63Qz0GB7TKPoeeZQmWCaz7T1+9vBnypkYWg==
```

#### <a name="from-stream"></a> `> ssri.fromStream(stream, [opts]) -> Promise<Integrity>`

Returns a Promise of an Integrity object calculated by reading data from
a given `stream`.

It accepts both `opts.algorithms` and `opts.options`, which are documented as
part of [`ssri.fromData`](#from-data).

Additionally, `opts.Promise` may be passed in to inject a Promise library of
choice. By default, ssri will use Node's built-in Promises.

##### Example

```javascript
ssri.fromStream(fs.createReadStream('index.js'), {
algorithms: ['sha1', 'sha512']
}).then(integrity => {
return ssri.checkStream(fs.createReadStream('index.js'), integrity)
}) // succeeds
```

#### <a name="check-data"></a> `> ssri.checkData(data, sri, [opts]) -> Algorithm|false`

Verifies `data` integrity against an `sri` argument. `data` may be either a
`String` or a `Buffer`, and `sri` can be any `Integrity`-like, or a `String`
that [`ssri.parse`](#parse) can turn into one.

If verification succeeds, `checkData` will return the name of the algorithm that
was used for verification (a truthy value). Otherwise, it will return `false`.

If `opts.pickAlgorithm` is provided, it will be passed two algorithms as
arguments. ssri will prioritize whichever of the two algorithms is returned by
this function. Note that the function may be called multiple times, and it
**must** return one of the two algorithms provided. By default, ssri will make
a best-effort to pick the strongest/most reliable of the given algorithms. It
may intentionally deprioritize algorithms with known vulnerabilities.

##### Example

```javascript
const data = fs.readFileSync('index.js')
ssri.checkData(data, ssri.fromData(data)) // -> 'sha512'
ssri.checkData(data, 'sha256-l981iLWj8kurw4UbNy8Lpxqdzd7UOxS50Glhv8FwfZ0')
ssri.checkData(data, 'sha1-BaDDigEST') // -> false
```

#### <a name="check-stream"></a> `> ssri.checkStream(stream, sri, [opts]) -> Promise<Algorithm>`

Verifies the contents of `stream` against an `sri` argument. `stream` will be
consumed in its entirety by this process. `sri` can be any `Integrity`-like, or
a `String` that [`ssri.parse`](#parse) can turn into one.

`checkStream` will return a Promise that either resolves to the string name of
the algorithm that verification was done with, or, if the verification fails or
an error happens with `stream`, the Promise will be rejected.

If the Promise is rejected because verification failed, the returned error will
have `err.code` as `EBADCHECKSUM`.

If `opts.pickAlgorithm` is provided, it will be passed two algorithms as
arguments. ssri will prioritize whichever of the two algorithms is returned by
this function. Note that the function may be called multiple times, and it
**must** return one of the two algorithms provided. By default, ssri will make
a best-effort to pick the strongest/most reliable of the given algorithms. It
may intentionally deprioritize algorithms with known vulnerabilities.

##### Example

```javascript
const integrity = ssri.fromData(fs.readFileSync('index.js'))

ssri.checkStream(
fs.createReadStream('index.js'),
integrity
) // -> Promise<'sha512'>

ssri.checkStream(
fs.createReadStream('index.js'),
'sha256-l981iLWj8kurw4UbNy8Lpxqdzd7UOxS50Glhv8FwfZ0'
) // -> Promise<'sha256'>

ssri.checkStream(
fs.createReadStream('index.js'),
'sha1-BaDDigEST'
) // -> Promise<Error<EBADCHECKSUM>>
```

#### <a name="create-checker-stream"></a> `> createCheckerStream(sri, [opts]) -> CheckerStream`

Returns a `Through` stream that data can be piped through in order to check it
against `sri`. `sri` can be any `Integrity`-like, or a `String` that
[`ssri.parse`](#parse) can turn into one.

If verification fails, the returned stream will error with an `EBADCHECKSUM`
error code.

If `opts.pickAlgorithm` is provided, it will be passed two algorithms as
arguments. ssri will prioritize whichever of the two algorithms is returned by
this function. Note that the function may be called multiple times, and it
**must** return one of the two algorithms provided. By default, ssri will make
a best-effort to pick the strongest/most reliable of the given algorithms. It
may intentionally deprioritize algorithms with known vulnerabilities.

##### Example

```javascript
const integrity = ssri.fromData(fs.readFileSync('index.js'))
fs.createReadStream('index.js')
.pipe(ssri.checkStream(integrity))
```

0 comments on commit 2dc11d1

Please sign in to comment.