multiformats
Advanced tools
Comparing version 9.3.0 to 9.3.1
@@ -9,3 +9,3 @@ 'use strict'; | ||
var base32 = require('../src/bases/base32.js'); | ||
var base64Browser = require('../src/bases/base64-browser.js'); | ||
var base64 = require('../src/bases/base64.js'); | ||
var sha2Browser = require('../src/hashes/sha2-browser.js'); | ||
@@ -343,4 +343,4 @@ var util = require('util'); | ||
same(cid$1._baseCache.size, 0); | ||
same(cid$1.toString(base64Browser.base64), 'mAXASILp4Fr+PAc/qQUFA3l2uIiOwA2Gjlhd6nLQQ/2HyABWt'); | ||
same(cid$1._baseCache.get(base64Browser.base64.prefix), 'mAXASILp4Fr+PAc/qQUFA3l2uIiOwA2Gjlhd6nLQQ/2HyABWt'); | ||
same(cid$1.toString(base64.base64), 'mAXASILp4Fr+PAc/qQUFA3l2uIiOwA2Gjlhd6nLQQ/2HyABWt'); | ||
same(cid$1._baseCache.get(base64.base64.prefix), 'mAXASILp4Fr+PAc/qQUFA3l2uIiOwA2Gjlhd6nLQQ/2HyABWt'); | ||
same(cid$1._baseCache.has(base32.base32.prefix), false); | ||
@@ -350,3 +350,3 @@ const base32String = 'bafybeif2pall7dybz7vecqka3zo24irdwabwdi4wc55jznaq75q7eaavvu'; | ||
same(cid$1._baseCache.get(base32.base32.prefix), base32String); | ||
same(cid$1.toString(base64Browser.base64), 'mAXASILp4Fr+PAc/qQUFA3l2uIiOwA2Gjlhd6nLQQ/2HyABWt'); | ||
same(cid$1.toString(base64.base64), 'mAXASILp4Fr+PAc/qQUFA3l2uIiOwA2Gjlhd6nLQQ/2HyABWt'); | ||
}); | ||
@@ -471,3 +471,3 @@ test('should cache string representation when constructed with one', () => { | ||
const msg = 'To parse non base32 or base58btc encoded CID multibase decoder must be provided'; | ||
await testThrow(() => cid.CID.parse(cid$1.toString(base64Browser.base64)), msg); | ||
await testThrow(() => cid.CID.parse(cid$1.toString(base64.base64)), msg); | ||
}); | ||
@@ -477,3 +477,3 @@ test('parses base64 encoded CIDv1 if base64 is provided', async () => { | ||
const cid$1 = cid.CID.create(1, 112, hash); | ||
const parsed = cid.CID.parse(cid$1.toString(base64Browser.base64), base64Browser.base64); | ||
const parsed = cid.CID.parse(cid$1.toString(base64.base64), base64.base64); | ||
digestsame(cid$1, parsed); | ||
@@ -480,0 +480,0 @@ }); |
@@ -9,3 +9,3 @@ 'use strict'; | ||
var base58 = require('../src/bases/base58.js'); | ||
var base64Browser = require('../src/bases/base64-browser.js'); | ||
var base64$1 = require('../src/bases/base64.js'); | ||
@@ -20,3 +20,3 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } | ||
...base58, | ||
...base64Browser | ||
...base64$1 | ||
}; | ||
@@ -36,5 +36,2 @@ const same = assert__default['default'].deepStrictEqual; | ||
describe('multibase', () => { | ||
test('browser', () => { | ||
same(!!base64Browser.__browser, !!process.browser); | ||
}); | ||
for (const base of [ | ||
@@ -82,2 +79,7 @@ base16, | ||
const buff = bytes.fromString('test'); | ||
const nonPrintableBuff = Uint8Array.from([ | ||
239, | ||
250, | ||
254 | ||
]); | ||
const baseTest = bases => { | ||
@@ -93,2 +95,9 @@ for (const base of Object.values(bases)) { | ||
}); | ||
test(`encode/decode ${ base.name } with non-printable values`, () => { | ||
const encoded = base.encode(nonPrintableBuff); | ||
const decoded = base.decode(encoded); | ||
same(decoded, nonPrintableBuff); | ||
same(encoded, base.encoder.encode(nonPrintableBuff)); | ||
same(nonPrintableBuff, base.decoder.decode(encoded)); | ||
}); | ||
} | ||
@@ -110,5 +119,5 @@ } | ||
describe('base64', () => { | ||
baseTest(base64Browser); | ||
baseTest(base64$1); | ||
}); | ||
describe('multibase mismatch', () => { | ||
test('multibase mismatch', () => { | ||
const b64 = base64.encode(bytes.fromString('test')); | ||
@@ -118,3 +127,3 @@ const msg = `Unable to decode multibase string "${ b64 }", base32 decoder only supports inputs prefixed with ${ base32.prefix }`; | ||
}); | ||
describe('decoder composition', () => { | ||
test('decoder composition', () => { | ||
const base = base32.decoder.or(base58btc.decoder); | ||
@@ -132,2 +141,9 @@ const b32 = base32.encode(bytes.fromString('test')); | ||
}); | ||
test('truncated data', () => { | ||
const b64 = base64.encode(Uint8Array.from([ | ||
245, | ||
250 | ||
])); | ||
testThrow(() => base64.decode(b64.substring(0, b64.length - 1)), 'unexpected end of data'); | ||
}); | ||
}); |
@@ -111,5 +111,2 @@ 'use strict'; | ||
}); | ||
test('browser', () => { | ||
same(sha2Browser.__browser, !!process.browser); | ||
}); | ||
}); |
@@ -9,3 +9,3 @@ 'use strict'; | ||
var base32 = require('../src/bases/base32.js'); | ||
var base64Import = require('../src/bases/base64-import.js'); | ||
var base64 = require('../src/bases/base64.js'); | ||
var sha2 = require('../src/hashes/sha2.js'); | ||
@@ -343,4 +343,4 @@ var util = require('util'); | ||
same(cid$1._baseCache.size, 0); | ||
same(cid$1.toString(base64Import.base64), 'mAXASILp4Fr+PAc/qQUFA3l2uIiOwA2Gjlhd6nLQQ/2HyABWt'); | ||
same(cid$1._baseCache.get(base64Import.base64.prefix), 'mAXASILp4Fr+PAc/qQUFA3l2uIiOwA2Gjlhd6nLQQ/2HyABWt'); | ||
same(cid$1.toString(base64.base64), 'mAXASILp4Fr+PAc/qQUFA3l2uIiOwA2Gjlhd6nLQQ/2HyABWt'); | ||
same(cid$1._baseCache.get(base64.base64.prefix), 'mAXASILp4Fr+PAc/qQUFA3l2uIiOwA2Gjlhd6nLQQ/2HyABWt'); | ||
same(cid$1._baseCache.has(base32.base32.prefix), false); | ||
@@ -350,3 +350,3 @@ const base32String = 'bafybeif2pall7dybz7vecqka3zo24irdwabwdi4wc55jznaq75q7eaavvu'; | ||
same(cid$1._baseCache.get(base32.base32.prefix), base32String); | ||
same(cid$1.toString(base64Import.base64), 'mAXASILp4Fr+PAc/qQUFA3l2uIiOwA2Gjlhd6nLQQ/2HyABWt'); | ||
same(cid$1.toString(base64.base64), 'mAXASILp4Fr+PAc/qQUFA3l2uIiOwA2Gjlhd6nLQQ/2HyABWt'); | ||
}); | ||
@@ -471,3 +471,3 @@ test('should cache string representation when constructed with one', () => { | ||
const msg = 'To parse non base32 or base58btc encoded CID multibase decoder must be provided'; | ||
await testThrow(() => cid.CID.parse(cid$1.toString(base64Import.base64)), msg); | ||
await testThrow(() => cid.CID.parse(cid$1.toString(base64.base64)), msg); | ||
}); | ||
@@ -477,3 +477,3 @@ test('parses base64 encoded CIDv1 if base64 is provided', async () => { | ||
const cid$1 = cid.CID.create(1, 112, hash); | ||
const parsed = cid.CID.parse(cid$1.toString(base64Import.base64), base64Import.base64); | ||
const parsed = cid.CID.parse(cid$1.toString(base64.base64), base64.base64); | ||
digestsame(cid$1, parsed); | ||
@@ -480,0 +480,0 @@ }); |
@@ -9,3 +9,3 @@ 'use strict'; | ||
var base58 = require('../src/bases/base58.js'); | ||
var base64Import = require('../src/bases/base64-import.js'); | ||
var base64$1 = require('../src/bases/base64.js'); | ||
@@ -20,3 +20,3 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } | ||
...base58, | ||
...base64Import | ||
...base64$1 | ||
}; | ||
@@ -36,5 +36,2 @@ const same = assert__default['default'].deepStrictEqual; | ||
describe('multibase', () => { | ||
test('browser', () => { | ||
same(!!base64Import.__browser, !!process.browser); | ||
}); | ||
for (const base of [ | ||
@@ -82,2 +79,7 @@ base16, | ||
const buff = bytes.fromString('test'); | ||
const nonPrintableBuff = Uint8Array.from([ | ||
239, | ||
250, | ||
254 | ||
]); | ||
const baseTest = bases => { | ||
@@ -93,2 +95,9 @@ for (const base of Object.values(bases)) { | ||
}); | ||
test(`encode/decode ${ base.name } with non-printable values`, () => { | ||
const encoded = base.encode(nonPrintableBuff); | ||
const decoded = base.decode(encoded); | ||
same(decoded, nonPrintableBuff); | ||
same(encoded, base.encoder.encode(nonPrintableBuff)); | ||
same(nonPrintableBuff, base.decoder.decode(encoded)); | ||
}); | ||
} | ||
@@ -110,5 +119,5 @@ } | ||
describe('base64', () => { | ||
baseTest(base64Import); | ||
baseTest(base64$1); | ||
}); | ||
describe('multibase mismatch', () => { | ||
test('multibase mismatch', () => { | ||
const b64 = base64.encode(bytes.fromString('test')); | ||
@@ -118,3 +127,3 @@ const msg = `Unable to decode multibase string "${ b64 }", base32 decoder only supports inputs prefixed with ${ base32.prefix }`; | ||
}); | ||
describe('decoder composition', () => { | ||
test('decoder composition', () => { | ||
const base = base32.decoder.or(base58btc.decoder); | ||
@@ -132,2 +141,9 @@ const b32 = base32.encode(bytes.fromString('test')); | ||
}); | ||
test('truncated data', () => { | ||
const b64 = base64.encode(Uint8Array.from([ | ||
245, | ||
250 | ||
])); | ||
testThrow(() => base64.decode(b64.substring(0, b64.length - 1)), 'unexpected end of data'); | ||
}); | ||
}); |
@@ -111,5 +111,2 @@ 'use strict'; | ||
}); | ||
test('browser', () => { | ||
same(sha2.__browser, !!process.browser); | ||
}); | ||
}); |
@@ -87,21 +87,2 @@ 'use strict'; | ||
} | ||
const withAlphabet = ({name, prefix, encode, decode, alphabet}) => from({ | ||
name, | ||
prefix, | ||
encode: input => encode(input, alphabet), | ||
decode: input => { | ||
for (const char of input) { | ||
if (alphabet.indexOf(char) < 0) { | ||
throw new Error(`invalid ${ name } character`); | ||
} | ||
} | ||
return decode(input, alphabet); | ||
} | ||
}); | ||
const withSettings = ({name, prefix, settings, encode, decode}) => from({ | ||
name, | ||
prefix, | ||
encode: input => encode(input, settings), | ||
decode: input => decode(input, settings) | ||
}); | ||
const from = ({name, prefix, encode, decode}) => new Codec(name, prefix, encode, decode); | ||
@@ -115,2 +96,68 @@ const implement = alphabet => { | ||
}; | ||
const decode = (string, alphabet, bitsPerChar, name) => { | ||
const codes = {}; | ||
for (let i = 0; i < alphabet.length; ++i) { | ||
codes[alphabet[i]] = i; | ||
} | ||
let end = string.length; | ||
while (string[end - 1] === '=') { | ||
--end; | ||
} | ||
const out = new Uint8Array(end * bitsPerChar / 8 | 0); | ||
let bits = 0; | ||
let buffer = 0; | ||
let written = 0; | ||
for (let i = 0; i < end; ++i) { | ||
const value = codes[string[i]]; | ||
if (value === undefined) { | ||
throw new SyntaxError(`invalid ${ name } character`); | ||
} | ||
buffer = buffer << bitsPerChar | value; | ||
bits += bitsPerChar; | ||
if (bits >= 8) { | ||
bits -= 8; | ||
out[written++] = 255 & buffer >> bits; | ||
} | ||
} | ||
if (bits >= bitsPerChar || 255 & buffer << 8 - bits) { | ||
throw new SyntaxError('unexpected end of data'); | ||
} | ||
return out; | ||
}; | ||
const encode = (data, alphabet, bitsPerChar) => { | ||
const pad = alphabet[alphabet.length - 1] === '='; | ||
const mask = (1 << bitsPerChar) - 1; | ||
let out = ''; | ||
let bits = 0; | ||
let buffer = 0; | ||
for (let i = 0; i < data.length; ++i) { | ||
buffer = buffer << 8 | data[i]; | ||
bits += 8; | ||
while (bits > bitsPerChar) { | ||
bits -= bitsPerChar; | ||
out += alphabet[mask & buffer >> bits]; | ||
} | ||
} | ||
if (bits) { | ||
out += alphabet[mask & buffer << bitsPerChar - bits]; | ||
} | ||
if (pad) { | ||
while (out.length * bitsPerChar & 7) { | ||
out += '='; | ||
} | ||
} | ||
return out; | ||
}; | ||
const rfc4648 = ({name, prefix, bitsPerChar, alphabet}) => { | ||
return from({ | ||
prefix, | ||
name, | ||
encode(input) { | ||
return encode(input, alphabet, bitsPerChar); | ||
}, | ||
decode(input) { | ||
return decode(input, alphabet, bitsPerChar, name); | ||
} | ||
}); | ||
}; | ||
@@ -120,3 +167,2 @@ exports.Codec = Codec; | ||
exports.implement = implement; | ||
exports.withAlphabet = withAlphabet; | ||
exports.withSettings = withSettings; | ||
exports.rfc4648 = rfc4648; |
@@ -5,18 +5,15 @@ 'use strict'; | ||
var bytes = require('../bytes.js'); | ||
var base = require('./base.js'); | ||
const base16 = base.withAlphabet({ | ||
const base16 = base.rfc4648({ | ||
prefix: 'f', | ||
name: 'base16', | ||
alphabet: '0123456789abcdef', | ||
encode: bytes.toHex, | ||
decode: bytes.fromHex | ||
bitsPerChar: 4 | ||
}); | ||
const base16upper = base.withAlphabet({ | ||
const base16upper = base.rfc4648({ | ||
prefix: 'F', | ||
name: 'base16upper', | ||
alphabet: '0123456789ABCDEF', | ||
encode: bytes.toHex, | ||
decode: bytes.fromHex | ||
bitsPerChar: 4 | ||
}); | ||
@@ -23,0 +20,0 @@ |
@@ -7,109 +7,55 @@ 'use strict'; | ||
function decode(input, alphabet) { | ||
input = input.replace(/=/g, ''); | ||
const length = input.length; | ||
let bits = 0; | ||
let value = 0; | ||
let index = 0; | ||
const output = new Uint8Array(length * 5 / 8 | 0); | ||
for (let i = 0; i < length; i++) { | ||
value = value << 5 | alphabet.indexOf(input[i]); | ||
bits += 5; | ||
if (bits >= 8) { | ||
output[index++] = value >>> bits - 8 & 255; | ||
bits -= 8; | ||
} | ||
} | ||
return output; | ||
} | ||
function encode(buffer, alphabet) { | ||
const length = buffer.byteLength; | ||
const view = new Uint8Array(buffer); | ||
const padding = alphabet.indexOf('=') === alphabet.length - 1; | ||
if (padding) { | ||
alphabet = alphabet.substring(0, alphabet.length - 1); | ||
} | ||
let bits = 0; | ||
let value = 0; | ||
let output = ''; | ||
for (let i = 0; i < length; i++) { | ||
value = value << 8 | view[i]; | ||
bits += 8; | ||
while (bits >= 5) { | ||
output += alphabet[value >>> bits - 5 & 31]; | ||
bits -= 5; | ||
} | ||
} | ||
if (bits > 0) { | ||
output += alphabet[value << 5 - bits & 31]; | ||
} | ||
if (padding) { | ||
while (output.length % 8 !== 0) { | ||
output += '='; | ||
} | ||
} | ||
return output; | ||
} | ||
const base32 = base.withAlphabet({ | ||
const base32 = base.rfc4648({ | ||
prefix: 'b', | ||
name: 'base32', | ||
alphabet: 'abcdefghijklmnopqrstuvwxyz234567', | ||
encode, | ||
decode | ||
bitsPerChar: 5 | ||
}); | ||
const base32upper = base.withAlphabet({ | ||
const base32upper = base.rfc4648({ | ||
prefix: 'B', | ||
name: 'base32upper', | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', | ||
encode, | ||
decode | ||
bitsPerChar: 5 | ||
}); | ||
const base32pad = base.withAlphabet({ | ||
const base32pad = base.rfc4648({ | ||
prefix: 'c', | ||
name: 'base32pad', | ||
alphabet: 'abcdefghijklmnopqrstuvwxyz234567=', | ||
encode, | ||
decode | ||
alphabet: 'abcdefghijklmnopqrstuvwxyz234567', | ||
bitsPerChar: 5 | ||
}); | ||
const base32padupper = base.withAlphabet({ | ||
const base32padupper = base.rfc4648({ | ||
prefix: 'C', | ||
name: 'base32padupper', | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=', | ||
encode, | ||
decode | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', | ||
bitsPerChar: 5 | ||
}); | ||
const base32hex = base.withAlphabet({ | ||
const base32hex = base.rfc4648({ | ||
prefix: 'v', | ||
name: 'base32hex', | ||
alphabet: '0123456789abcdefghijklmnopqrstuv', | ||
encode, | ||
decode | ||
bitsPerChar: 5 | ||
}); | ||
const base32hexupper = base.withAlphabet({ | ||
const base32hexupper = base.rfc4648({ | ||
prefix: 'V', | ||
name: 'base32hexupper', | ||
alphabet: '0123456789ABCDEFGHIJKLMNOPQRSTUV', | ||
encode, | ||
decode | ||
bitsPerChar: 5 | ||
}); | ||
const base32hexpad = base.withAlphabet({ | ||
const base32hexpad = base.rfc4648({ | ||
prefix: 't', | ||
name: 'base32hexpad', | ||
alphabet: '0123456789abcdefghijklmnopqrstuv=', | ||
encode, | ||
decode | ||
alphabet: '0123456789abcdefghijklmnopqrstuv', | ||
bitsPerChar: 5 | ||
}); | ||
const base32hexpadupper = base.withAlphabet({ | ||
const base32hexpadupper = base.rfc4648({ | ||
prefix: 'T', | ||
name: 'base32hexpadupper', | ||
alphabet: '0123456789ABCDEFGHIJKLMNOPQRSTUV=', | ||
encode, | ||
decode | ||
alphabet: '0123456789ABCDEFGHIJKLMNOPQRSTUV', | ||
bitsPerChar: 5 | ||
}); | ||
const base32z = base.withAlphabet({ | ||
const base32z = base.rfc4648({ | ||
prefix: 'h', | ||
name: 'base32z', | ||
alphabet: 'ybndrfg8ejkmcpqxot1uwisza345h769', | ||
encode, | ||
decode | ||
bitsPerChar: 5 | ||
}); | ||
@@ -116,0 +62,0 @@ |
'use strict'; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
var base = require('./base.js'); | ||
const alphabetSettings = alphabet => ({ | ||
alphabet, | ||
padding: alphabet.indexOf('=') > -1, | ||
url: alphabet.indexOf('-') > -1 && alphabet.indexOf('_') > -1 | ||
const base64 = base.rfc4648({ | ||
prefix: 'm', | ||
name: 'base64', | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', | ||
bitsPerChar: 6 | ||
}); | ||
var b64 = b64 => { | ||
const encode = (input, {url, padding}) => { | ||
let output = b64.encode(input); | ||
if (url) { | ||
output = output.replace(/\+/g, '-').replace(/\//g, '_'); | ||
} | ||
const pad = output.indexOf('='); | ||
if (pad > 0 && !padding) { | ||
output = output.substring(0, pad); | ||
} | ||
return output; | ||
}; | ||
const decode = (input, {alphabet}) => { | ||
for (const char of input) { | ||
if (alphabet.indexOf(char) < 0) { | ||
throw new Error('invalid base64 character'); | ||
} | ||
} | ||
return b64.decode(input); | ||
}; | ||
const codec = ({name, prefix, alphabet}) => base.withSettings({ | ||
name, | ||
prefix, | ||
settings: alphabetSettings(alphabet), | ||
decode, | ||
encode | ||
}); | ||
return { | ||
b64, | ||
__browser: b64.__browser, | ||
base64: codec({ | ||
name: 'base64', | ||
prefix: 'm', | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' | ||
}), | ||
base64pad: codec({ | ||
name: 'base64pad', | ||
prefix: 'M', | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' | ||
}), | ||
base64url: codec({ | ||
name: 'base64url', | ||
prefix: 'u', | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_' | ||
}), | ||
base64urlpad: codec({ | ||
name: 'base64urlpad', | ||
prefix: 'U', | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=' | ||
}) | ||
}; | ||
}; | ||
const base64pad = base.rfc4648({ | ||
prefix: 'M', | ||
name: 'base64pad', | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=', | ||
bitsPerChar: 6 | ||
}); | ||
const base64url = base.rfc4648({ | ||
prefix: 'u', | ||
name: 'base64url', | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', | ||
bitsPerChar: 6 | ||
}); | ||
const base64urlpad = base.rfc4648({ | ||
prefix: 'U', | ||
name: 'base64urlpad', | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=', | ||
bitsPerChar: 6 | ||
}); | ||
module.exports = b64; | ||
exports.base64 = base64; | ||
exports.base64pad = base64pad; | ||
exports.base64url = base64url; | ||
exports.base64urlpad = base64urlpad; |
@@ -18,6 +18,4 @@ 'use strict'; | ||
}); | ||
const __browser = true; | ||
exports.__browser = __browser; | ||
exports.sha256 = sha256; | ||
exports.sha512 = sha512; |
@@ -23,6 +23,4 @@ 'use strict'; | ||
}); | ||
const __browser = false; | ||
exports.__browser = __browser; | ||
exports.sha256 = sha256; | ||
exports.sha512 = sha512; |
@@ -14,3 +14,3 @@ import OLDCID from 'cids'; | ||
import { base32 } from '../src/bases/base32.js'; | ||
import { base64 } from '../src/bases/base64-browser.js'; | ||
import { base64 } from '../src/bases/base64.js'; | ||
import { | ||
@@ -17,0 +17,0 @@ sha256, |
@@ -7,3 +7,3 @@ import * as bytes from '../src/bytes.js'; | ||
import * as b58 from '../src/bases/base58.js'; | ||
import * as b64 from '../src/bases/base64-browser.js'; | ||
import * as b64 from '../src/bases/base64.js'; | ||
const {base16, base32, base58btc, base64} = { | ||
@@ -28,5 +28,2 @@ ...b16, | ||
describe('multibase', () => { | ||
test('browser', () => { | ||
same(!!b64.__browser, !!process.browser); | ||
}); | ||
for (const base of [ | ||
@@ -74,2 +71,7 @@ base16, | ||
const buff = bytes.fromString('test'); | ||
const nonPrintableBuff = Uint8Array.from([ | ||
239, | ||
250, | ||
254 | ||
]); | ||
const baseTest = bases => { | ||
@@ -85,2 +87,9 @@ for (const base of Object.values(bases)) { | ||
}); | ||
test(`encode/decode ${ base.name } with non-printable values`, () => { | ||
const encoded = base.encode(nonPrintableBuff); | ||
const decoded = base.decode(encoded); | ||
same(decoded, nonPrintableBuff); | ||
same(encoded, base.encoder.encode(nonPrintableBuff)); | ||
same(nonPrintableBuff, base.decoder.decode(encoded)); | ||
}); | ||
} | ||
@@ -104,3 +113,3 @@ } | ||
}); | ||
describe('multibase mismatch', () => { | ||
test('multibase mismatch', () => { | ||
const b64 = base64.encode(bytes.fromString('test')); | ||
@@ -110,3 +119,3 @@ const msg = `Unable to decode multibase string "${ b64 }", base32 decoder only supports inputs prefixed with ${ base32.prefix }`; | ||
}); | ||
describe('decoder composition', () => { | ||
test('decoder composition', () => { | ||
const base = base32.decoder.or(base58btc.decoder); | ||
@@ -124,2 +133,9 @@ const b32 = base32.encode(bytes.fromString('test')); | ||
}); | ||
test('truncated data', () => { | ||
const b64 = base64.encode(Uint8Array.from([ | ||
245, | ||
250 | ||
])); | ||
testThrow(() => base64.decode(b64.substring(0, b64.length - 1)), 'unexpected end of data'); | ||
}); | ||
}); |
@@ -12,4 +12,3 @@ import { | ||
sha256, | ||
sha512, | ||
__browser | ||
sha512 | ||
} from '../src/hashes/sha2-browser.js'; | ||
@@ -115,5 +114,2 @@ import { identity } from '../src/hashes/identity.js'; | ||
}); | ||
test('browser', () => { | ||
same(__browser, !!process.browser); | ||
}); | ||
}); |
@@ -14,3 +14,3 @@ import OLDCID from 'cids'; | ||
import { base32 } from '../src/bases/base32.js'; | ||
import { base64 } from '../src/bases/base64-import.js'; | ||
import { base64 } from '../src/bases/base64.js'; | ||
import { | ||
@@ -17,0 +17,0 @@ sha256, |
@@ -7,3 +7,3 @@ import * as bytes from '../src/bytes.js'; | ||
import * as b58 from '../src/bases/base58.js'; | ||
import * as b64 from '../src/bases/base64-import.js'; | ||
import * as b64 from '../src/bases/base64.js'; | ||
const {base16, base32, base58btc, base64} = { | ||
@@ -28,5 +28,2 @@ ...b16, | ||
describe('multibase', () => { | ||
test('browser', () => { | ||
same(!!b64.__browser, !!process.browser); | ||
}); | ||
for (const base of [ | ||
@@ -74,2 +71,7 @@ base16, | ||
const buff = bytes.fromString('test'); | ||
const nonPrintableBuff = Uint8Array.from([ | ||
239, | ||
250, | ||
254 | ||
]); | ||
const baseTest = bases => { | ||
@@ -85,2 +87,9 @@ for (const base of Object.values(bases)) { | ||
}); | ||
test(`encode/decode ${ base.name } with non-printable values`, () => { | ||
const encoded = base.encode(nonPrintableBuff); | ||
const decoded = base.decode(encoded); | ||
same(decoded, nonPrintableBuff); | ||
same(encoded, base.encoder.encode(nonPrintableBuff)); | ||
same(nonPrintableBuff, base.decoder.decode(encoded)); | ||
}); | ||
} | ||
@@ -104,3 +113,3 @@ } | ||
}); | ||
describe('multibase mismatch', () => { | ||
test('multibase mismatch', () => { | ||
const b64 = base64.encode(bytes.fromString('test')); | ||
@@ -110,3 +119,3 @@ const msg = `Unable to decode multibase string "${ b64 }", base32 decoder only supports inputs prefixed with ${ base32.prefix }`; | ||
}); | ||
describe('decoder composition', () => { | ||
test('decoder composition', () => { | ||
const base = base32.decoder.or(base58btc.decoder); | ||
@@ -124,2 +133,9 @@ const b32 = base32.encode(bytes.fromString('test')); | ||
}); | ||
test('truncated data', () => { | ||
const b64 = base64.encode(Uint8Array.from([ | ||
245, | ||
250 | ||
])); | ||
testThrow(() => base64.decode(b64.substring(0, b64.length - 1)), 'unexpected end of data'); | ||
}); | ||
}); |
@@ -12,4 +12,3 @@ import { | ||
sha256, | ||
sha512, | ||
__browser | ||
sha512 | ||
} from '../src/hashes/sha2.js'; | ||
@@ -115,5 +114,2 @@ import { identity } from '../src/hashes/identity.js'; | ||
}); | ||
test('browser', () => { | ||
same(__browser, !!process.browser); | ||
}); | ||
}); |
@@ -82,21 +82,2 @@ import baseX from '../../vendor/base-x.js'; | ||
} | ||
export const withAlphabet = ({name, prefix, encode, decode, alphabet}) => from({ | ||
name, | ||
prefix, | ||
encode: input => encode(input, alphabet), | ||
decode: input => { | ||
for (const char of input) { | ||
if (alphabet.indexOf(char) < 0) { | ||
throw new Error(`invalid ${ name } character`); | ||
} | ||
} | ||
return decode(input, alphabet); | ||
} | ||
}); | ||
export const withSettings = ({name, prefix, settings, encode, decode}) => from({ | ||
name, | ||
prefix, | ||
encode: input => encode(input, settings), | ||
decode: input => decode(input, settings) | ||
}); | ||
export const from = ({name, prefix, encode, decode}) => new Codec(name, prefix, encode, decode); | ||
@@ -109,2 +90,68 @@ export const implement = alphabet => { | ||
}; | ||
}; | ||
const decode = (string, alphabet, bitsPerChar, name) => { | ||
const codes = {}; | ||
for (let i = 0; i < alphabet.length; ++i) { | ||
codes[alphabet[i]] = i; | ||
} | ||
let end = string.length; | ||
while (string[end - 1] === '=') { | ||
--end; | ||
} | ||
const out = new Uint8Array(end * bitsPerChar / 8 | 0); | ||
let bits = 0; | ||
let buffer = 0; | ||
let written = 0; | ||
for (let i = 0; i < end; ++i) { | ||
const value = codes[string[i]]; | ||
if (value === undefined) { | ||
throw new SyntaxError(`invalid ${ name } character`); | ||
} | ||
buffer = buffer << bitsPerChar | value; | ||
bits += bitsPerChar; | ||
if (bits >= 8) { | ||
bits -= 8; | ||
out[written++] = 255 & buffer >> bits; | ||
} | ||
} | ||
if (bits >= bitsPerChar || 255 & buffer << 8 - bits) { | ||
throw new SyntaxError('unexpected end of data'); | ||
} | ||
return out; | ||
}; | ||
const encode = (data, alphabet, bitsPerChar) => { | ||
const pad = alphabet[alphabet.length - 1] === '='; | ||
const mask = (1 << bitsPerChar) - 1; | ||
let out = ''; | ||
let bits = 0; | ||
let buffer = 0; | ||
for (let i = 0; i < data.length; ++i) { | ||
buffer = buffer << 8 | data[i]; | ||
bits += 8; | ||
while (bits > bitsPerChar) { | ||
bits -= bitsPerChar; | ||
out += alphabet[mask & buffer >> bits]; | ||
} | ||
} | ||
if (bits) { | ||
out += alphabet[mask & buffer << bitsPerChar - bits]; | ||
} | ||
if (pad) { | ||
while (out.length * bitsPerChar & 7) { | ||
out += '='; | ||
} | ||
} | ||
return out; | ||
}; | ||
export const rfc4648 = ({name, prefix, bitsPerChar, alphabet}) => { | ||
return from({ | ||
prefix, | ||
name, | ||
encode(input) { | ||
return encode(input, alphabet, bitsPerChar); | ||
}, | ||
decode(input) { | ||
return decode(input, alphabet, bitsPerChar, name); | ||
} | ||
}); | ||
}; |
@@ -1,19 +0,13 @@ | ||
import { | ||
fromHex, | ||
toHex | ||
} from '../bytes.js'; | ||
import { withAlphabet } from './base.js'; | ||
export const base16 = withAlphabet({ | ||
import { rfc4648 } from './base.js'; | ||
export const base16 = rfc4648({ | ||
prefix: 'f', | ||
name: 'base16', | ||
alphabet: '0123456789abcdef', | ||
encode: toHex, | ||
decode: fromHex | ||
bitsPerChar: 4 | ||
}); | ||
export const base16upper = withAlphabet({ | ||
export const base16upper = rfc4648({ | ||
prefix: 'F', | ||
name: 'base16upper', | ||
alphabet: '0123456789ABCDEF', | ||
encode: toHex, | ||
decode: fromHex | ||
bitsPerChar: 4 | ||
}); |
@@ -1,109 +0,55 @@ | ||
import { withAlphabet } from './base.js'; | ||
function decode(input, alphabet) { | ||
input = input.replace(/=/g, ''); | ||
const length = input.length; | ||
let bits = 0; | ||
let value = 0; | ||
let index = 0; | ||
const output = new Uint8Array(length * 5 / 8 | 0); | ||
for (let i = 0; i < length; i++) { | ||
value = value << 5 | alphabet.indexOf(input[i]); | ||
bits += 5; | ||
if (bits >= 8) { | ||
output[index++] = value >>> bits - 8 & 255; | ||
bits -= 8; | ||
} | ||
} | ||
return output; | ||
} | ||
function encode(buffer, alphabet) { | ||
const length = buffer.byteLength; | ||
const view = new Uint8Array(buffer); | ||
const padding = alphabet.indexOf('=') === alphabet.length - 1; | ||
if (padding) { | ||
alphabet = alphabet.substring(0, alphabet.length - 1); | ||
} | ||
let bits = 0; | ||
let value = 0; | ||
let output = ''; | ||
for (let i = 0; i < length; i++) { | ||
value = value << 8 | view[i]; | ||
bits += 8; | ||
while (bits >= 5) { | ||
output += alphabet[value >>> bits - 5 & 31]; | ||
bits -= 5; | ||
} | ||
} | ||
if (bits > 0) { | ||
output += alphabet[value << 5 - bits & 31]; | ||
} | ||
if (padding) { | ||
while (output.length % 8 !== 0) { | ||
output += '='; | ||
} | ||
} | ||
return output; | ||
} | ||
export const base32 = withAlphabet({ | ||
import { rfc4648 } from './base.js'; | ||
export const base32 = rfc4648({ | ||
prefix: 'b', | ||
name: 'base32', | ||
alphabet: 'abcdefghijklmnopqrstuvwxyz234567', | ||
encode, | ||
decode | ||
bitsPerChar: 5 | ||
}); | ||
export const base32upper = withAlphabet({ | ||
export const base32upper = rfc4648({ | ||
prefix: 'B', | ||
name: 'base32upper', | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', | ||
encode, | ||
decode | ||
bitsPerChar: 5 | ||
}); | ||
export const base32pad = withAlphabet({ | ||
export const base32pad = rfc4648({ | ||
prefix: 'c', | ||
name: 'base32pad', | ||
alphabet: 'abcdefghijklmnopqrstuvwxyz234567=', | ||
encode, | ||
decode | ||
alphabet: 'abcdefghijklmnopqrstuvwxyz234567', | ||
bitsPerChar: 5 | ||
}); | ||
export const base32padupper = withAlphabet({ | ||
export const base32padupper = rfc4648({ | ||
prefix: 'C', | ||
name: 'base32padupper', | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=', | ||
encode, | ||
decode | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', | ||
bitsPerChar: 5 | ||
}); | ||
export const base32hex = withAlphabet({ | ||
export const base32hex = rfc4648({ | ||
prefix: 'v', | ||
name: 'base32hex', | ||
alphabet: '0123456789abcdefghijklmnopqrstuv', | ||
encode, | ||
decode | ||
bitsPerChar: 5 | ||
}); | ||
export const base32hexupper = withAlphabet({ | ||
export const base32hexupper = rfc4648({ | ||
prefix: 'V', | ||
name: 'base32hexupper', | ||
alphabet: '0123456789ABCDEFGHIJKLMNOPQRSTUV', | ||
encode, | ||
decode | ||
bitsPerChar: 5 | ||
}); | ||
export const base32hexpad = withAlphabet({ | ||
export const base32hexpad = rfc4648({ | ||
prefix: 't', | ||
name: 'base32hexpad', | ||
alphabet: '0123456789abcdefghijklmnopqrstuv=', | ||
encode, | ||
decode | ||
alphabet: '0123456789abcdefghijklmnopqrstuv', | ||
bitsPerChar: 5 | ||
}); | ||
export const base32hexpadupper = withAlphabet({ | ||
export const base32hexpadupper = rfc4648({ | ||
prefix: 'T', | ||
name: 'base32hexpadupper', | ||
alphabet: '0123456789ABCDEFGHIJKLMNOPQRSTUV=', | ||
encode, | ||
decode | ||
alphabet: '0123456789ABCDEFGHIJKLMNOPQRSTUV', | ||
bitsPerChar: 5 | ||
}); | ||
export const base32z = withAlphabet({ | ||
export const base32z = rfc4648({ | ||
prefix: 'h', | ||
name: 'base32z', | ||
alphabet: 'ybndrfg8ejkmcpqxot1uwisza345h769', | ||
encode, | ||
decode | ||
bitsPerChar: 5 | ||
}); |
@@ -1,58 +0,25 @@ | ||
import { withSettings } from './base.js'; | ||
const alphabetSettings = alphabet => ({ | ||
alphabet, | ||
padding: alphabet.indexOf('=') > -1, | ||
url: alphabet.indexOf('-') > -1 && alphabet.indexOf('_') > -1 | ||
import { rfc4648 } from './base.js'; | ||
export const base64 = rfc4648({ | ||
prefix: 'm', | ||
name: 'base64', | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', | ||
bitsPerChar: 6 | ||
}); | ||
export default b64 => { | ||
const encode = (input, {url, padding}) => { | ||
let output = b64.encode(input); | ||
if (url) { | ||
output = output.replace(/\+/g, '-').replace(/\//g, '_'); | ||
} | ||
const pad = output.indexOf('='); | ||
if (pad > 0 && !padding) { | ||
output = output.substring(0, pad); | ||
} | ||
return output; | ||
}; | ||
const decode = (input, {alphabet}) => { | ||
for (const char of input) { | ||
if (alphabet.indexOf(char) < 0) { | ||
throw new Error('invalid base64 character'); | ||
} | ||
} | ||
return b64.decode(input); | ||
}; | ||
const codec = ({name, prefix, alphabet}) => withSettings({ | ||
name, | ||
prefix, | ||
settings: alphabetSettings(alphabet), | ||
decode, | ||
encode | ||
}); | ||
return { | ||
b64, | ||
__browser: b64.__browser, | ||
base64: codec({ | ||
name: 'base64', | ||
prefix: 'm', | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' | ||
}), | ||
base64pad: codec({ | ||
name: 'base64pad', | ||
prefix: 'M', | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' | ||
}), | ||
base64url: codec({ | ||
name: 'base64url', | ||
prefix: 'u', | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_' | ||
}), | ||
base64urlpad: codec({ | ||
name: 'base64urlpad', | ||
prefix: 'U', | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=' | ||
}) | ||
}; | ||
}; | ||
export const base64pad = rfc4648({ | ||
prefix: 'M', | ||
name: 'base64pad', | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=', | ||
bitsPerChar: 6 | ||
}); | ||
export const base64url = rfc4648({ | ||
prefix: 'u', | ||
name: 'base64url', | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', | ||
bitsPerChar: 6 | ||
}); | ||
export const base64urlpad = rfc4648({ | ||
prefix: 'U', | ||
name: 'base64urlpad', | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=', | ||
bitsPerChar: 6 | ||
}); |
@@ -12,3 +12,2 @@ import { from } from './hasher.js'; | ||
encode: sha('SHA-512') | ||
}); | ||
export const __browser = true; | ||
}); |
@@ -13,3 +13,2 @@ import crypto from 'crypto'; | ||
encode: input => coerce(crypto.createHash('sha512').update(input).digest()) | ||
}); | ||
export const __browser = false; | ||
}); |
{ | ||
"name": "multiformats", | ||
"version": "9.3.0", | ||
"version": "9.3.1", | ||
"description": "Interface for multihash, multicodec, multibase and CID", | ||
@@ -48,2 +48,7 @@ "main": "./cjs/src/index.js", | ||
}, | ||
"./basics": { | ||
"browser": "./esm/src/basics.js", | ||
"require": "./cjs/src/basics.js", | ||
"import": "./esm/src/basics.js" | ||
}, | ||
"./block": { | ||
@@ -75,5 +80,5 @@ "browser": "./esm/src/block.js", | ||
"./bases/base64": { | ||
"browser": "./esm/src/bases/base64-browser.js", | ||
"require": "./cjs/src/bases/base64-import.js", | ||
"import": "./esm/src/bases/base64-import.js" | ||
"browser": "./esm/src/bases/base64.js", | ||
"require": "./cjs/src/bases/base64.js", | ||
"import": "./esm/src/bases/base64.js" | ||
}, | ||
@@ -144,5 +149,2 @@ "./hashes/hasher": { | ||
"*": { | ||
"bases/base64": [ | ||
"types/bases/base64-import.d.ts" | ||
], | ||
"*": [ | ||
@@ -159,2 +161,3 @@ "types/*" | ||
"./cid": "./cjs/src/cid.js", | ||
"./basics": "./cjs/src/basics.js", | ||
"./block": "./cjs/src/block.js", | ||
@@ -165,3 +168,3 @@ "./bases/base16": "./cjs/src/bases/base16.js", | ||
"./bases/base58": "./cjs/src/bases/base58.js", | ||
"./bases/base64": "./cjs/src/bases/base64-browser.js", | ||
"./bases/base64": "./cjs/src/bases/base64.js", | ||
"./hashes/hasher": "./cjs/src/hashes/hasher.js", | ||
@@ -168,0 +171,0 @@ "./hashes/digest": "./cjs/src/hashes/digest.js", |
@@ -229,48 +229,2 @@ import baseX from '../../vendor/base-x.js' | ||
* @param {Prefix} options.prefix | ||
* @param {string} options.alphabet | ||
* @param {(input:Uint8Array, alphabet:string) => string} options.encode | ||
* @param {(input:string, alphabet:string) => Uint8Array} options.decode | ||
*/ | ||
export const withAlphabet = ({ name, prefix, encode, decode, alphabet }) => | ||
from({ | ||
name, | ||
prefix, | ||
encode: input => encode(input, alphabet), | ||
decode: input => { | ||
for (const char of input) { | ||
if (alphabet.indexOf(char) < 0) { | ||
throw new Error(`invalid ${name} character`) | ||
} | ||
} | ||
return decode(input, alphabet) | ||
} | ||
}) | ||
/** | ||
* @template {string} Base | ||
* @template {string} Prefix | ||
* @template Settings | ||
* | ||
* @param {Object} options | ||
* @param {Base} options.name | ||
* @param {Prefix} options.prefix | ||
* @param {Settings} options.settings | ||
* @param {(input:Uint8Array, settings:Settings) => string} options.encode | ||
* @param {(input:string, settings:Settings) => Uint8Array} options.decode | ||
*/ | ||
export const withSettings = ({ name, prefix, settings, encode, decode }) => | ||
from({ | ||
name, | ||
prefix, | ||
encode: (input) => encode(input, settings), | ||
decode: (input) => decode(input, settings) | ||
}) | ||
/** | ||
* @template {string} Base | ||
* @template {string} Prefix | ||
* @param {Object} options | ||
* @param {Base} options.name | ||
* @param {Prefix} options.prefix | ||
* @param {(bytes:Uint8Array) => string} options.encode | ||
@@ -296,1 +250,117 @@ * @param {(input:string) => Uint8Array} options.decode | ||
} | ||
/** | ||
* @param {string} string | ||
* @param {string} alphabet | ||
* @param {number} bitsPerChar | ||
* @param {string} name | ||
* @returns {Uint8Array} | ||
*/ | ||
const decode = (string, alphabet, bitsPerChar, name) => { | ||
// Build the character lookup table: | ||
/** @type {Record<string, number>} */ | ||
const codes = {} | ||
for (let i = 0; i < alphabet.length; ++i) { | ||
codes[alphabet[i]] = i | ||
} | ||
// Count the padding bytes: | ||
let end = string.length | ||
while (string[end - 1] === '=') { | ||
--end | ||
} | ||
// Allocate the output: | ||
const out = new Uint8Array((end * bitsPerChar / 8) | 0) | ||
// Parse the data: | ||
let bits = 0 // Number of bits currently in the buffer | ||
let buffer = 0 // Bits waiting to be written out, MSB first | ||
let written = 0 // Next byte to write | ||
for (let i = 0; i < end; ++i) { | ||
// Read one character from the string: | ||
const value = codes[string[i]] | ||
if (value === undefined) { | ||
throw new SyntaxError(`invalid ${name} character`) | ||
} | ||
// Append the bits to the buffer: | ||
buffer = (buffer << bitsPerChar) | value | ||
bits += bitsPerChar | ||
// Write out some bits if the buffer has a byte's worth: | ||
if (bits >= 8) { | ||
bits -= 8 | ||
out[written++] = 0xff & (buffer >> bits) | ||
} | ||
} | ||
// Verify that we have received just enough bits: | ||
if (bits >= bitsPerChar || 0xff & (buffer << (8 - bits))) { | ||
throw new SyntaxError('unexpected end of data') | ||
} | ||
return out | ||
} | ||
/** | ||
* @param {Uint8Array} data | ||
* @param {string} alphabet | ||
* @param {number} bitsPerChar | ||
* @returns {string} | ||
*/ | ||
const encode = (data, alphabet, bitsPerChar) => { | ||
const pad = alphabet[alphabet.length - 1] === '=' | ||
const mask = (1 << bitsPerChar) - 1 | ||
let out = '' | ||
let bits = 0 // Number of bits currently in the buffer | ||
let buffer = 0 // Bits waiting to be written out, MSB first | ||
for (let i = 0; i < data.length; ++i) { | ||
// Slurp data into the buffer: | ||
buffer = (buffer << 8) | data[i] | ||
bits += 8 | ||
// Write out as much as we can: | ||
while (bits > bitsPerChar) { | ||
bits -= bitsPerChar | ||
out += alphabet[mask & (buffer >> bits)] | ||
} | ||
} | ||
// Partial character: | ||
if (bits) { | ||
out += alphabet[mask & (buffer << (bitsPerChar - bits))] | ||
} | ||
// Add padding characters until we hit a byte boundary: | ||
if (pad) { | ||
while ((out.length * bitsPerChar) & 7) { | ||
out += '=' | ||
} | ||
} | ||
return out | ||
} | ||
/** | ||
* RFC4648 Factory | ||
* | ||
* @param {Object} options | ||
* @param {string} options.name | ||
* @param {string} options.prefix | ||
* @param {string} options.alphabet | ||
* @param {number} options.bitsPerChar | ||
*/ | ||
export const rfc4648 = ({ name, prefix, bitsPerChar, alphabet }) => { | ||
return from({ | ||
prefix, | ||
name, | ||
encode (input) { | ||
return encode(input, alphabet, bitsPerChar) | ||
}, | ||
decode (input) { | ||
return decode(input, alphabet, bitsPerChar, name) | ||
} | ||
}) | ||
} |
// @ts-check | ||
import { fromHex, toHex } from '../bytes.js' | ||
import { withAlphabet } from './base.js' | ||
import { rfc4648 } from './base.js' | ||
export const base16 = withAlphabet({ | ||
export const base16 = rfc4648({ | ||
prefix: 'f', | ||
name: 'base16', | ||
alphabet: '0123456789abcdef', | ||
encode: toHex, | ||
decode: fromHex | ||
bitsPerChar: 4 | ||
}) | ||
export const base16upper = withAlphabet({ | ||
export const base16upper = rfc4648({ | ||
prefix: 'F', | ||
name: 'base16upper', | ||
alphabet: '0123456789ABCDEF', | ||
encode: toHex, | ||
decode: fromHex | ||
bitsPerChar: 4 | ||
}) |
@@ -1,140 +0,64 @@ | ||
import { withAlphabet } from './base.js' | ||
import { rfc4648 } from './base.js' | ||
/** | ||
* @param {string} input | ||
* @param {string} alphabet | ||
*/ | ||
function decode (input, alphabet) { | ||
input = input.replace(/=/g, '') | ||
const length = input.length | ||
let bits = 0 | ||
let value = 0 | ||
let index = 0 | ||
const output = new Uint8Array((length * 5 / 8) | 0) | ||
for (let i = 0; i < length; i++) { | ||
value = (value << 5) | alphabet.indexOf(input[i]) | ||
bits += 5 | ||
if (bits >= 8) { | ||
output[index++] = (value >>> (bits - 8)) & 255 | ||
bits -= 8 | ||
} | ||
} | ||
return output | ||
} | ||
/** | ||
* @param {Uint8Array} buffer | ||
* @param {string} alphabet | ||
*/ | ||
function encode (buffer, alphabet) { | ||
const length = buffer.byteLength | ||
const view = new Uint8Array(buffer) | ||
const padding = alphabet.indexOf('=') === alphabet.length - 1 | ||
if (padding) { | ||
alphabet = alphabet.substring(0, alphabet.length - 1) | ||
} | ||
let bits = 0 | ||
let value = 0 | ||
let output = '' | ||
for (let i = 0; i < length; i++) { | ||
value = (value << 8) | view[i] | ||
bits += 8 | ||
while (bits >= 5) { | ||
output += alphabet[(value >>> (bits - 5)) & 31] | ||
bits -= 5 | ||
} | ||
} | ||
if (bits > 0) { | ||
output += alphabet[(value << (5 - bits)) & 31] | ||
} | ||
if (padding) { | ||
while ((output.length % 8) !== 0) { | ||
output += '=' | ||
} | ||
} | ||
return output | ||
} | ||
export const base32 = withAlphabet({ | ||
export const base32 = rfc4648({ | ||
prefix: 'b', | ||
name: 'base32', | ||
alphabet: 'abcdefghijklmnopqrstuvwxyz234567', | ||
encode, | ||
decode | ||
bitsPerChar: 5 | ||
}) | ||
export const base32upper = withAlphabet({ | ||
export const base32upper = rfc4648({ | ||
prefix: 'B', | ||
name: 'base32upper', | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', | ||
encode, | ||
decode | ||
bitsPerChar: 5 | ||
}) | ||
export const base32pad = withAlphabet({ | ||
export const base32pad = rfc4648({ | ||
prefix: 'c', | ||
name: 'base32pad', | ||
alphabet: 'abcdefghijklmnopqrstuvwxyz234567=', | ||
encode, | ||
decode | ||
alphabet: 'abcdefghijklmnopqrstuvwxyz234567', | ||
bitsPerChar: 5 | ||
}) | ||
export const base32padupper = withAlphabet({ | ||
export const base32padupper = rfc4648({ | ||
prefix: 'C', | ||
name: 'base32padupper', | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=', | ||
encode, | ||
decode | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', | ||
bitsPerChar: 5 | ||
}) | ||
export const base32hex = withAlphabet({ | ||
export const base32hex = rfc4648({ | ||
prefix: 'v', | ||
name: 'base32hex', | ||
alphabet: '0123456789abcdefghijklmnopqrstuv', | ||
encode, | ||
decode | ||
bitsPerChar: 5 | ||
}) | ||
export const base32hexupper = withAlphabet({ | ||
export const base32hexupper = rfc4648({ | ||
prefix: 'V', | ||
name: 'base32hexupper', | ||
alphabet: '0123456789ABCDEFGHIJKLMNOPQRSTUV', | ||
encode, | ||
decode | ||
bitsPerChar: 5 | ||
}) | ||
export const base32hexpad = withAlphabet({ | ||
export const base32hexpad = rfc4648({ | ||
prefix: 't', | ||
name: 'base32hexpad', | ||
alphabet: '0123456789abcdefghijklmnopqrstuv=', | ||
encode, | ||
decode | ||
alphabet: '0123456789abcdefghijklmnopqrstuv', | ||
bitsPerChar: 5 | ||
}) | ||
export const base32hexpadupper = withAlphabet({ | ||
export const base32hexpadupper = rfc4648({ | ||
prefix: 'T', | ||
name: 'base32hexpadupper', | ||
alphabet: '0123456789ABCDEFGHIJKLMNOPQRSTUV=', | ||
encode, | ||
decode | ||
alphabet: '0123456789ABCDEFGHIJKLMNOPQRSTUV', | ||
bitsPerChar: 5 | ||
}) | ||
export const base32z = withAlphabet({ | ||
export const base32z = rfc4648({ | ||
prefix: 'h', | ||
name: 'base32z', | ||
alphabet: 'ybndrfg8ejkmcpqxot1uwisza345h769', | ||
encode, | ||
decode | ||
bitsPerChar: 5 | ||
}) |
// @ts-check | ||
import { withSettings } from './base.js' | ||
import { rfc4648 } from './base.js' | ||
/** | ||
* The alphabet is only used to know: | ||
* 1. If padding is enabled (must contain '=') | ||
* 2. If the output must be url-safe (must contain '-' and '_') | ||
* 3. If the input of the output function is valid | ||
* The alphabets from RFC 4648 are always used. | ||
* @typedef {Object} Settings | ||
* @property {boolean} padding | ||
* @property {boolean} url | ||
* @property {string} alphabet | ||
* | ||
* @param {string} alphabet | ||
* @returns {Settings} | ||
*/ | ||
const alphabetSettings = (alphabet) => ({ | ||
alphabet, | ||
padding: alphabet.indexOf('=') > -1, | ||
url: alphabet.indexOf('-') > -1 && alphabet.indexOf('_') > -1 | ||
export const base64 = rfc4648({ | ||
prefix: 'm', | ||
name: 'base64', | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', | ||
bitsPerChar: 6 | ||
}) | ||
/** | ||
* @param {Object} b64 | ||
* @param {(text:string) => Uint8Array} b64.decode | ||
* @param {(bytes:Uint8Array) => string} b64.encode | ||
* @param {boolean} b64.__browser | ||
*/ | ||
export default b64 => { | ||
/** | ||
* @param {Uint8Array} input | ||
* @param {Settings} settings | ||
*/ | ||
const encode = (input, { url, padding }) => { | ||
let output = b64.encode(input) | ||
export const base64pad = rfc4648({ | ||
prefix: 'M', | ||
name: 'base64pad', | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=', | ||
bitsPerChar: 6 | ||
}) | ||
if (url) { | ||
output = output.replace(/\+/g, '-').replace(/\//g, '_') | ||
} | ||
export const base64url = rfc4648({ | ||
prefix: 'u', | ||
name: 'base64url', | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', | ||
bitsPerChar: 6 | ||
}) | ||
const pad = output.indexOf('=') | ||
if (pad > 0 && !padding) { | ||
output = output.substring(0, pad) | ||
} | ||
return output | ||
} | ||
/** | ||
* @param {string} input | ||
* @param {Settings} settings | ||
*/ | ||
const decode = (input, { alphabet }) => { | ||
for (const char of input) { | ||
if (alphabet.indexOf(char) < 0) { | ||
throw new Error('invalid base64 character') | ||
} | ||
} | ||
return b64.decode(input) | ||
} | ||
/** | ||
* @template {string} Base | ||
* @template {string} Prefix | ||
* @param {Object} options | ||
* @param {Base} options.name | ||
* @param {Prefix} options.prefix | ||
* @param {string} options.alphabet | ||
*/ | ||
const codec = ({ name, prefix, alphabet }) => withSettings({ | ||
name, | ||
prefix, | ||
settings: alphabetSettings(alphabet), | ||
decode, | ||
encode | ||
}) | ||
return { | ||
b64, | ||
__browser: b64.__browser, | ||
base64: codec({ | ||
name: 'base64', | ||
prefix: 'm', | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' | ||
}), | ||
base64pad: codec({ | ||
name: 'base64pad', | ||
prefix: 'M', | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' | ||
}), | ||
base64url: codec({ | ||
name: 'base64url', | ||
prefix: 'u', | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_' | ||
}), | ||
base64urlpad: codec({ | ||
name: 'base64urlpad', | ||
prefix: 'U', | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=' | ||
}) | ||
} | ||
} | ||
export const base64urlpad = rfc4648({ | ||
prefix: 'U', | ||
name: 'base64urlpad', | ||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=', | ||
bitsPerChar: 6 | ||
}) |
// @ts-check | ||
import * as base16 from './bases/base16.js' | ||
import * as base32 from './bases/base32.js' | ||
import * as base36 from './bases/base36.js' | ||
import * as base58 from './bases/base58.js' | ||
import * as base64 from './bases/base64.js' | ||
import * as sha2 from './hashes/sha2.js' | ||
import * as identity from './hashes/identity.js' | ||
@@ -12,6 +16,6 @@ import * as raw from './codecs/raw.js' | ||
const bases = { ...base32, ...base58 } | ||
const hashes = { ...sha2 } | ||
const bases = { ...base16, ...base32, ...base36, ...base58, ...base64 } | ||
const hashes = { ...sha2, ...identity } | ||
const codecs = { raw, json } | ||
export { CID, hasher, digest, varint, bytes, hashes, bases, codecs } |
@@ -25,3 +25,1 @@ /* global crypto */ | ||
}) | ||
export const __browser = true |
@@ -18,3 +18,1 @@ // @ts-check | ||
}) | ||
export const __browser = false |
@@ -27,6 +27,2 @@ /* globals describe, it */ | ||
describe('multibase', () => { | ||
test('browser', () => { | ||
same(!!b64.__browser, !!process.browser) | ||
}) | ||
for (const base of [base16, base32, base58btc, base64]) { | ||
@@ -73,2 +69,4 @@ describe(`basics ${base.name}`, () => { | ||
const buff = bytes.fromString('test') | ||
const nonPrintableBuff = Uint8Array.from([239, 250, 254]) | ||
const baseTest = bases => { | ||
@@ -84,2 +82,10 @@ for (const base of Object.values(bases)) { | ||
}) | ||
test(`encode/decode ${base.name} with non-printable values`, () => { | ||
const encoded = base.encode(nonPrintableBuff) | ||
const decoded = base.decode(encoded) | ||
same(decoded, nonPrintableBuff) | ||
same(encoded, base.encoder.encode(nonPrintableBuff)) | ||
same(nonPrintableBuff, base.decoder.decode(encoded)) | ||
}) | ||
} | ||
@@ -104,3 +110,3 @@ } | ||
describe('multibase mismatch', () => { | ||
test('multibase mismatch', () => { | ||
const b64 = base64.encode(bytes.fromString('test')) | ||
@@ -111,3 +117,3 @@ const msg = `Unable to decode multibase string "${b64}", base32 decoder only supports inputs prefixed with ${base32.prefix}` | ||
describe('decoder composition', () => { | ||
test('decoder composition', () => { | ||
const base = base32.decoder.or(base58btc.decoder) | ||
@@ -131,2 +137,8 @@ | ||
}) | ||
test('truncated data', () => { | ||
const b64 = base64.encode(Uint8Array.from([245, 250])) | ||
testThrow(() => base64.decode(b64.substring(0, b64.length - 1)), 'unexpected end of data') | ||
}) | ||
}) |
@@ -7,3 +7,3 @@ /* globals describe, it */ | ||
import crypto from 'crypto' | ||
import { sha256, sha512, __browser } from 'multiformats/hashes/sha2' | ||
import { sha256, sha512 } from 'multiformats/hashes/sha2' | ||
import { identity } from 'multiformats/hashes/identity' | ||
@@ -114,5 +114,2 @@ import { decode as decodeDigest, create as createDigest } from 'multiformats/hashes/digest' | ||
}) | ||
test('browser', () => { | ||
same(__browser, !!process.browser) | ||
}) | ||
}) |
@@ -39,16 +39,2 @@ /** | ||
} | ||
export function withAlphabet<Base extends string, Prefix extends string>({ name, prefix, encode, decode, alphabet }: { | ||
name: Base; | ||
prefix: Prefix; | ||
alphabet: string; | ||
encode: (input: Uint8Array, alphabet: string) => string; | ||
decode: (input: string, alphabet: string) => Uint8Array; | ||
}): Codec<Base, Prefix>; | ||
export function withSettings<Base extends string, Prefix extends string, Settings>({ name, prefix, settings, encode, decode }: { | ||
name: Base; | ||
prefix: Prefix; | ||
settings: Settings; | ||
encode: (input: Uint8Array, settings: Settings) => string; | ||
decode: (input: string, settings: Settings) => Uint8Array; | ||
}): Codec<Base, Prefix>; | ||
export function from<Base extends string, Prefix extends string>({ name, prefix, encode, decode }: { | ||
@@ -67,2 +53,8 @@ name: Base; | ||
}; | ||
export function rfc4648({ name, prefix, bitsPerChar, alphabet }: { | ||
name: string; | ||
prefix: string; | ||
alphabet: string; | ||
bitsPerChar: number; | ||
}): Codec<string, string>; | ||
export type BaseEncoder = import('./interface').BaseEncoder; | ||
@@ -69,0 +61,0 @@ export type BaseDecoder = import('./interface').BaseDecoder; |
@@ -1,3 +0,3 @@ | ||
export const base16: import("./base.js").Codec<"base16", "f">; | ||
export const base16upper: import("./base.js").Codec<"base16upper", "F">; | ||
export const base16: import("./base.js").Codec<string, string>; | ||
export const base16upper: import("./base.js").Codec<string, string>; | ||
//# sourceMappingURL=base16.d.ts.map |
@@ -1,10 +0,10 @@ | ||
export const base32: import("./base.js").Codec<"base32", "b">; | ||
export const base32upper: import("./base.js").Codec<"base32upper", "B">; | ||
export const base32pad: import("./base.js").Codec<"base32pad", "c">; | ||
export const base32padupper: import("./base.js").Codec<"base32padupper", "C">; | ||
export const base32hex: import("./base.js").Codec<"base32hex", "v">; | ||
export const base32hexupper: import("./base.js").Codec<"base32hexupper", "V">; | ||
export const base32hexpad: import("./base.js").Codec<"base32hexpad", "t">; | ||
export const base32hexpadupper: import("./base.js").Codec<"base32hexpadupper", "T">; | ||
export const base32z: import("./base.js").Codec<"base32z", "h">; | ||
export const base32: import("./base.js").Codec<string, string>; | ||
export const base32upper: import("./base.js").Codec<string, string>; | ||
export const base32pad: import("./base.js").Codec<string, string>; | ||
export const base32padupper: import("./base.js").Codec<string, string>; | ||
export const base32hex: import("./base.js").Codec<string, string>; | ||
export const base32hexupper: import("./base.js").Codec<string, string>; | ||
export const base32hexpad: import("./base.js").Codec<string, string>; | ||
export const base32hexpadupper: import("./base.js").Codec<string, string>; | ||
export const base32z: import("./base.js").Codec<string, string>; | ||
//# sourceMappingURL=base32.d.ts.map |
@@ -1,30 +0,5 @@ | ||
declare function _default(b64: { | ||
decode: (text: string) => Uint8Array; | ||
encode: (bytes: Uint8Array) => string; | ||
__browser: boolean; | ||
}): { | ||
b64: { | ||
decode: (text: string) => Uint8Array; | ||
encode: (bytes: Uint8Array) => string; | ||
__browser: boolean; | ||
}; | ||
__browser: boolean; | ||
base64: import("./base.js").Codec<"base64", "m">; | ||
base64pad: import("./base.js").Codec<"base64pad", "M">; | ||
base64url: import("./base.js").Codec<"base64url", "u">; | ||
base64urlpad: import("./base.js").Codec<"base64urlpad", "U">; | ||
}; | ||
export default _default; | ||
/** | ||
* The alphabet is only used to know: | ||
* 1. If padding is enabled (must contain '=') | ||
* 2. If the output must be url-safe (must contain '-' and '_') | ||
* 3. If the input of the output function is valid | ||
* The alphabets from RFC 4648 are always used. | ||
*/ | ||
export type Settings = { | ||
padding: boolean; | ||
url: boolean; | ||
alphabet: string; | ||
}; | ||
export const base64: import("./base.js").Codec<string, string>; | ||
export const base64pad: import("./base.js").Codec<string, string>; | ||
export const base64url: import("./base.js").Codec<string, string>; | ||
export const base64urlpad: import("./base.js").Codec<string, string>; | ||
//# sourceMappingURL=base64.d.ts.map |
@@ -7,18 +7,26 @@ import { CID } from "./index.js"; | ||
export const hashes: { | ||
identity: hasher.Hasher<"identity", 0>; | ||
sha256: hasher.Hasher<"sha2-256", 18>; | ||
sha512: hasher.Hasher<"sha2-512", 19>; | ||
__browser: false; | ||
}; | ||
export const bases: { | ||
base64: import("./bases/base.js").Codec<string, string>; | ||
base64pad: import("./bases/base.js").Codec<string, string>; | ||
base64url: import("./bases/base.js").Codec<string, string>; | ||
base64urlpad: import("./bases/base.js").Codec<string, string>; | ||
base58btc: import("./bases/base.js").Codec<"base58btc", "z">; | ||
base58flickr: import("./bases/base.js").Codec<"base58flickr", "Z">; | ||
base32: import("./bases/base.js").Codec<"base32", "b">; | ||
base32upper: import("./bases/base.js").Codec<"base32upper", "B">; | ||
base32pad: import("./bases/base.js").Codec<"base32pad", "c">; | ||
base32padupper: import("./bases/base.js").Codec<"base32padupper", "C">; | ||
base32hex: import("./bases/base.js").Codec<"base32hex", "v">; | ||
base32hexupper: import("./bases/base.js").Codec<"base32hexupper", "V">; | ||
base32hexpad: import("./bases/base.js").Codec<"base32hexpad", "t">; | ||
base32hexpadupper: import("./bases/base.js").Codec<"base32hexpadupper", "T">; | ||
base32z: import("./bases/base.js").Codec<"base32z", "h">; | ||
base36: import("./bases/base.js").Codec<"base36", "k">; | ||
base36upper: import("./bases/base.js").Codec<"base36upper", "K">; | ||
base32: import("./bases/base.js").Codec<string, string>; | ||
base32upper: import("./bases/base.js").Codec<string, string>; | ||
base32pad: import("./bases/base.js").Codec<string, string>; | ||
base32padupper: import("./bases/base.js").Codec<string, string>; | ||
base32hex: import("./bases/base.js").Codec<string, string>; | ||
base32hexupper: import("./bases/base.js").Codec<string, string>; | ||
base32hexpad: import("./bases/base.js").Codec<string, string>; | ||
base32hexpadupper: import("./bases/base.js").Codec<string, string>; | ||
base32z: import("./bases/base.js").Codec<string, string>; | ||
base16: import("./bases/base.js").Codec<string, string>; | ||
base16upper: import("./bases/base.js").Codec<string, string>; | ||
}; | ||
@@ -25,0 +33,0 @@ export namespace codecs { |
export const sha256: import("./hasher.js").Hasher<"sha2-256", 18>; | ||
export const sha512: import("./hasher.js").Hasher<"sha2-512", 19>; | ||
export const __browser: true; | ||
//# sourceMappingURL=sha2-browser.d.ts.map |
export const sha256: import("./hasher.js").Hasher<"sha2-256", 18>; | ||
export const sha512: import("./hasher.js").Hasher<"sha2-512", 19>; | ||
export const __browser: false; | ||
//# sourceMappingURL=sha2.d.ts.map |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
4
373662
158
10932