Skip to content
This repository was archived by the owner on Aug 24, 2021. It is now read-only.

fix: replace node buffers with uint8arrays #92

Merged
merged 1 commit into from
Aug 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 10 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
js-multihash
============
# js-multihash <!-- omit in toc -->

[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io)
[![](https://img.shields.io/badge/project-multiformats-blue.svg?style=flat-square)](https://github.com/multiformats/multiformats)
Expand All @@ -17,18 +16,18 @@ It is extended by [js-multihashing](https://github.com/multiformats/js-multihash
and [js-multihashing-async](https://github.com/multiformats/js-multihashing-async),
so give those a look as well.

## Lead Maintainer
## Lead Maintainer <!-- omit in toc -->

[Hugo Dias](http://github.com/hugomrdias/)

## Table of Contents
## Table of Contents <!-- omit in toc -->

- [Install](#install)
- [In Node.js through npm](#in-nodejs-through-npm)
- [Browser: Browserify, Webpack, other bundlers](#browser-browserify-webpack-other-bundlers)
- [In the Browser through `<script>` tag](#in-the-browser-through-script-tag)
- [Using npm](#using-npm)
- [Using a `<script>` tag](#using-a-script-tag)
- [Usage](#usage)
- [API](#api)
- [Update Constants](#update-constants)
- [Contribute](#contribute)
- [License](#license)

Expand Down Expand Up @@ -60,17 +59,17 @@ Loading this module through a script tag will make the ```Multihashes``` obj ava

```js
> var multihash = require('multihashes')
> var buf = new Buffer('0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33', 'hex')
> var bytes = Uint8Array.from([0, 1, 2, 3...])

> var encoded = multihash.encode(buf, 'sha1')
> var encoded = multihash.encode(bytes, 'sha1')
> console.log(encoded)
<Buffer 11 14 0b ee c7 b5 ea 3f 0f db c9 5d 0d d4 7f 3c 5b c2 75 da 8a 33>
<Uint8Array 11 14 0b ee c7 b5 ea 3f 0f db c9 5d 0d d4 7f 3c 5b c2 75 da 8a 33>

> multihash.decode(encoded)
{ code: 17,
name: 'sha1',
length: 20,
digest: <Buffer 0b ee c7 b5 ea 3f 0f db c9 5d 0d d4 7f 3c 5b c2 75 da 8a 33> }
digest: <Uint8Array 0b ee c7 b5 ea 3f 0f db c9 5d 0d d4 7f 3c 5b c2 75 da 8a 33> }
```

## API
Expand Down
11 changes: 4 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,12 @@
"main": "src/index.js",
"repository": "github:multiformats/js-multihash",
"dependencies": {
"buffer": "^5.6.0",
"multibase": "^2.0.0",
"varint": "^5.0.0",
"web-encoding": "^1.0.2"
"multibase": "^3.0.0",
"uint8arrays": "^1.0.0",
"varint": "^5.0.0"
},
"devDependencies": {
"aegir": "^24.0.0",
"chai": "^4.1.2",
"dirty-chai": "^2.0.1",
"aegir": "^25.0.0",
"ipfs-utils": "^2.3.1"
},
"contributors": [
Expand Down
50 changes: 20 additions & 30 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@
*/
'use strict'

const { Buffer } = require('buffer')
const multibase = require('multibase')
const varint = require('varint')
const { names } = require('./constants')
const { TextDecoder } = require('web-encoding')
const uint8ArrayToString = require('uint8arrays/to-string')
const uint8ArrayFromString = require('uint8arrays/from-string')
const uint8ArrayConcat = require('uint8arrays/concat')

const textDecoder = new TextDecoder()
const codes = {}
Expand All @@ -33,21 +34,17 @@ exports.toHexString = function toHexString (hash) {
throw new Error('must be passed a Uint8Array')
}

const buffer = Buffer.isBuffer(hash)
? hash
: Buffer.from(hash.buffer, hash.byteOffset, hash.byteLength)

return buffer.toString('hex')
return uint8ArrayToString(hash, 'base16')
}

/**
* Convert the given hex encoded string to a multihash.
*
* @param {string} hash
* @returns {Buffer}
* @returns {Uint8Array}
*/
exports.fromHexString = function fromHexString (hash) {
return Buffer.from(hash, 'hex')
return uint8ArrayFromString(hash, 'base16')
}

/**
Expand All @@ -68,7 +65,7 @@ exports.toB58String = function toB58String (hash) {
* Convert the given base58 encoded string to a multihash.
*
* @param {string|Uint8Array} hash
* @returns {Buffer}
* @returns {Uint8Array}
*/
exports.fromB58String = function fromB58String (hash) {
const encoded = hash instanceof Uint8Array
Expand All @@ -82,41 +79,38 @@ exports.fromB58String = function fromB58String (hash) {
* Decode a hash from the given multihash.
*
* @param {Uint8Array} bytes
* @returns {{code: number, name: string, length: number, digest: Buffer}} result
* @returns {{code: number, name: string, length: number, digest: Uint8Array}} result
*/
exports.decode = function decode (bytes) {
if (!(bytes instanceof Uint8Array)) {
throw new Error('multihash must be a Uint8Array')
}
let buf = Buffer.isBuffer(bytes)
? bytes
: Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength)

if (buf.length < 2) {
if (bytes.length < 2) {
throw new Error('multihash too short. must be > 2 bytes.')
}

const code = varint.decode(buf)
const code = varint.decode(bytes)
if (!exports.isValidCode(code)) {
throw new Error(`multihash unknown function code: 0x${code.toString(16)}`)
}
buf = buf.slice(varint.decode.bytes)
bytes = bytes.slice(varint.decode.bytes)

const len = varint.decode(buf)
const len = varint.decode(bytes)
if (len < 0) {
throw new Error(`multihash invalid length: ${len}`)
}
buf = buf.slice(varint.decode.bytes)
bytes = bytes.slice(varint.decode.bytes)

if (buf.length !== len) {
throw new Error(`multihash length inconsistent: 0x${buf.toString('hex')}`)
if (bytes.length !== len) {
throw new Error(`multihash length inconsistent: 0x${uint8ArrayToString(bytes, 'base16')}`)
}

return {
code,
name: codes[code],
length: len,
digest: buf
digest: bytes
}
}

Expand All @@ -128,7 +122,7 @@ exports.decode = function decode (bytes) {
* @param {Uint8Array} digest
* @param {string|number} code
* @param {number} [length]
* @returns {Buffer}
* @returns {Uint8Array}
*/
exports.encode = function encode (digest, code, length) {
if (!digest || code === undefined) {
Expand All @@ -152,11 +146,7 @@ exports.encode = function encode (digest, code, length) {

const hash = varint.encode(hashfn)
const len = varint.encode(length)
const buffer = Buffer.alloc(hash.length + len.length + digest.length)
buffer.set(hash, 0)
buffer.set(len, hash.length)
buffer.set(digest, hash.length + len.length)
return buffer
return uint8ArrayConcat([hash, len, digest], hash.length + len.length + digest.length)
}

/**
Expand Down Expand Up @@ -230,11 +220,11 @@ exports.validate = validate
* Returns a prefix from a valid multihash. Throws an error if it is not valid.
*
* @param {Uint8Array} multihash
* @returns {Buffer}
* @returns {Uint8Array}
* @throws {Error}
*/
exports.prefix = function prefix (multihash) {
validate(multihash)

return Buffer.from(multihash.buffer, multihash.byteOffset, 2)
return multihash.subarray(0, 2)
}
47 changes: 18 additions & 29 deletions test/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,15 @@
/* eslint max-nested-callbacks: off */
'use strict'

const chai = require('chai')
const dirtyChai = require('dirty-chai')
chai.use(dirtyChai)
const expect = chai.expect
const { expect } = require('aegir/utils/chai')
const multibase = require('multibase')
const { Buffer } = require('buffer')
const mh = require('../src')
const constants = require('../src/constants')
const validCases = require('./fixtures/valid')
const invalidCases = require('./fixtures/invalid')
const { TextEncoder } = require('web-encoding')
const uint8ArrayToString = require('uint8arrays/to-string')
const uint8ArrayFromString = require('uint8arrays/from-string')
const uint8ArrayEquals = require('uint8arrays/equals')

function sample (code, size, hex) {
const toHex = (i) => {
Expand All @@ -22,22 +20,13 @@ function sample (code, size, hex) {
const h = i.toString(16)
return h.length % 2 === 1 ? `0${h}` : h
}
return Buffer.from(`${toHex(code)}${toHex(size)}${hex}`, 'hex')
return uint8ArrayFromString(`${toHex(code)}${toHex(size)}${hex}`, 'base16')
}

const they = (description, test) => {
it(`${description} (Buffer)`, () => test({
encodeText: Buffer.from,
encodeHex: (text) => Buffer.from(text, 'hex')
}))

const textEncoder = new TextEncoder()
it(`${description} (Uint8Array)`, () => test({
encodeText: (text) => textEncoder.encode(text),
encodeHex: (text) => {
const { buffer, byteOffset, byteLength } = Buffer.from(text, 'hex')
return new Uint8Array(buffer, byteOffset, byteLength)
}
it(description, () => test({
encodeText: (text) => uint8ArrayFromString(text),
encodeHex: (text) => uint8ArrayFromString(text, 'base16')
}))
}

Expand All @@ -50,7 +39,7 @@ describe('multihash', () => {
expect(
mh.toHexString(buf)
).to.be.eql(
buf.toString('hex')
uint8ArrayToString(buf, 'base16')
)
})
})
Expand All @@ -70,9 +59,9 @@ describe('multihash', () => {
const code = test.encoding.code
const buf = mh.encode(encodeHex(test.hex), code)
expect(
mh.fromHexString(buf.toString('hex')).toString('hex')
uint8ArrayToString(mh.fromHexString(uint8ArrayToString(buf, 'base16')), 'base16')
).to.be.eql(
buf.toString('hex')
uint8ArrayToString(buf, 'base16')
)
})
})
Expand All @@ -86,7 +75,7 @@ describe('multihash', () => {
expect(
mh.toB58String(buf)
).to.be.eql(
multibase.encode('base58btc', buf).toString().slice(1)
uint8ArrayToString(multibase.encode('base58btc', buf)).slice(1)
)
})
})
Expand Down Expand Up @@ -125,7 +114,7 @@ describe('multihash', () => {
const code = test.encoding.code
const buf = sample(test.encoding.varint || code, test.size, test.hex)
const name = test.encoding.name
const d1 = Buffer.from(test.hex, 'hex')
const d1 = uint8ArrayFromString(test.hex, 'base16')
const length = d1.length

const r = mh.decode(buf)
Expand All @@ -134,7 +123,7 @@ describe('multihash', () => {
expect(r.code).to.equal(code)
expect(r.name).to.equal(name)
expect(r.length).to.equal(length)
expect(d1.equals(d2)).to.equal(true)
expect(uint8ArrayEquals(d1, d2)).to.equal(true)
})
})

Expand All @@ -160,9 +149,9 @@ describe('multihash', () => {

results.forEach((res) => {
expect(
res.toString('hex')
uint8ArrayToString(res, 'base16')
).to.be.eql(
buf.toString('hex')
uint8ArrayToString(buf, 'base16')
)
})
})
Expand Down Expand Up @@ -205,7 +194,7 @@ describe('multihash', () => {
).to.throw()
})

const longBuffer = Uint8Array.from(Buffer.alloc(150, 'a'))
const longBuffer = new Uint8Array(150).fill(0)
expect(
() => mh.validate(longBuffer)
).to.throw()
Expand Down Expand Up @@ -326,7 +315,7 @@ describe('multihash', () => {
they('prefix', ({ encodeText }) => {
const multihash = mh.encode(encodeText('hey'), 0x11, 3)
const prefix = mh.prefix(multihash)
expect(prefix.toString('hex')).to.eql('1103')
expect(uint8ArrayToString(prefix, 'base16')).to.eql('1103')
})

they('prefix throws on invalid multihash', ({ encodeText }) => {
Expand Down