UNPKG

check-ethereum-scanner

Version:

Safety checks for new Ethereum tokens

225 lines (191 loc) 4.98 kB
/** * Multihash implementation in JavaScript. * * @module multihash */ 'use strict' const { Buffer } = require('buffer') const multibase = require('multibase') const varint = require('varint') const cs = require('./constants') exports.names = cs.names exports.codes = cs.codes exports.defaultLengths = cs.defaultLengths /** * Convert the given multihash to a hex encoded string. * * @param {Buffer} hash * @returns {string} */ exports.toHexString = function toHexString (hash) { if (!Buffer.isBuffer(hash)) { throw new Error('must be passed a buffer') } return hash.toString('hex') } /** * Convert the given hex encoded string to a multihash. * * @param {string} hash * @returns {Buffer} */ exports.fromHexString = function fromHexString (hash) { return Buffer.from(hash, 'hex') } /** * Convert the given multihash to a base58 encoded string. * * @param {Buffer} hash * @returns {string} */ exports.toB58String = function toB58String (hash) { if (!Buffer.isBuffer(hash)) { throw new Error('must be passed a buffer') } return multibase.encode('base58btc', hash).toString().slice(1) } /** * Convert the given base58 encoded string to a multihash. * * @param {string|Buffer} hash * @returns {Buffer} */ exports.fromB58String = function fromB58String (hash) { let encoded = hash if (Buffer.isBuffer(hash)) { encoded = hash.toString() } return multibase.decode('z' + encoded) } /** * Decode a hash from the given multihash. * * @param {Buffer} buf * @returns {{code: number, name: string, length: number, digest: Buffer}} result */ exports.decode = function decode (buf) { if (!(Buffer.isBuffer(buf))) { throw new Error('multihash must be a Buffer') } if (buf.length < 2) { throw new Error('multihash too short. must be > 2 bytes.') } const code = varint.decode(buf) if (!exports.isValidCode(code)) { throw new Error(`multihash unknown function code: 0x${code.toString(16)}`) } buf = buf.slice(varint.decode.bytes) const len = varint.decode(buf) if (len < 0) { throw new Error(`multihash invalid length: ${len}`) } buf = buf.slice(varint.decode.bytes) if (buf.length !== len) { throw new Error(`multihash length inconsistent: 0x${buf.toString('hex')}`) } return { code: code, name: cs.codes[code], length: len, digest: buf } } /** * Encode a hash digest along with the specified function code. * * > **Note:** the length is derived from the length of the digest itself. * * @param {Buffer} digest * @param {string|number} code * @param {number} [length] * @returns {Buffer} */ exports.encode = function encode (digest, code, length) { if (!digest || code === undefined) { throw new Error('multihash encode requires at least two args: digest, code') } // ensure it's a hashfunction code. const hashfn = exports.coerceCode(code) if (!(Buffer.isBuffer(digest))) { throw new Error('digest should be a Buffer') } if (length == null) { length = digest.length } if (length && digest.length !== length) { throw new Error('digest length should be equal to specified length.') } return Buffer.concat([ Buffer.from(varint.encode(hashfn)), Buffer.from(varint.encode(length)), digest ]) } /** * Converts a hash function name into the matching code. * If passed a number it will return the number if it's a valid code. * @param {string|number} name * @returns {number} */ exports.coerceCode = function coerceCode (name) { let code = name if (typeof name === 'string') { if (cs.names[name] === undefined) { throw new Error(`Unrecognized hash function named: ${name}`) } code = cs.names[name] } if (typeof code !== 'number') { throw new Error(`Hash function code should be a number. Got: ${code}`) } if (cs.codes[code] === undefined && !exports.isAppCode(code)) { throw new Error(`Unrecognized function code: ${code}`) } return code } /** * Checks wether a code is part of the app range * * @param {number} code * @returns {boolean} */ exports.isAppCode = function appCode (code) { return code > 0 && code < 0x10 } /** * Checks whether a multihash code is valid. * * @param {number} code * @returns {boolean} */ exports.isValidCode = function validCode (code) { if (exports.isAppCode(code)) { return true } if (cs.codes[code]) { return true } return false } /** * Check if the given buffer is a valid multihash. Throws an error if it is not valid. * * @param {Buffer} multihash * @returns {undefined} * @throws {Error} */ function validate (multihash) { exports.decode(multihash) // throws if bad. } exports.validate = validate /** * Returns a prefix from a valid multihash. Throws an error if it is not valid. * * @param {Buffer} multihash * @returns {undefined} * @throws {Error} */ exports.prefix = function prefix (multihash) { validate(multihash) return multihash.slice(0, 2) }