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

Commit

Permalink
fix: base32 and base64 (#23)
Browse files Browse the repository at this point in the history
* fix: base32 and base64
feat: base32hex, base32pad, base32hexpad, base64urlpad, base64pad

* test: add base16 tests
  • Loading branch information
hacdias authored and daviddias committed Jan 1, 2018
1 parent 460e6ed commit a9b5150
Show file tree
Hide file tree
Showing 6 changed files with 207 additions and 9 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ build
# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules
yarn.lock
package-lock.json

dist
docs
81 changes: 81 additions & 0 deletions src/base32.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
'use strict'

function decode (input, alphabet) {
input = input.replace(new RegExp('=', 'g'), '')
let length = input.length

let bits = 0
let value = 0

let index = 0
let 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.buffer
}

function encode (buffer, alphabet) {
let length = buffer.byteLength
let view = new Uint8Array(buffer)
let padding = alphabet.indexOf('=') === alphabet.length - 1

if (padding) {
alphabet = alphabet.substring(0, alphabet.length - 2)
}

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
}

module.exports = function base32 (alphabet) {
return {
encode (input) {
if (typeof input === 'string') {
return encode(new Buffer(input), alphabet)
}

return encode(input, alphabet)
},
decode (input) {
for (let char of input) {
if (alphabet.indexOf(char) < 0) {
throw new Error('invalid base32 character')
}
}

return decode(input, alphabet)
}
}
}
49 changes: 49 additions & 0 deletions src/base64.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
'use strict'

module.exports = function base64 (alphabet) {
// 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.
const padding = alphabet.indexOf('=') > -1
const url = alphabet.indexOf('-') > -1 && alphabet.indexOf('_') > -1

return {
encode (input) {
let output = ''

if (typeof input === 'string') {
output = new Buffer(input).toString('base64')
} else {
output = input.toString('base64')
}

if (url) {
output = output.replace('+', '-')
output = output.replace('/', '_')
}

const pad = output.indexOf('=')
if (pad > 0 && !padding) {
output = output.substring(0, pad)
}

return output
},
decode (input) {
if (url) {
input = input.replace('+', '-')
input = input.replace('/', '_')
}

for (let char of input) {
if (alphabet.indexOf(char) < 0) {
throw new Error('invalid base64 character')
}
}

return new Buffer(input, 'base64')
}
}
}
16 changes: 11 additions & 5 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
const Base = require('./base.js')
const baseX = require('base-x')
const base16 = require('./base16')
const base32 = require('./base32')
const base64 = require('./base64')

// name, code, implementation, alphabet
const constants = [
Expand All @@ -11,13 +13,17 @@ const constants = [
['base8', '7', baseX, '01234567'],
['base10', '9', baseX, '0123456789'],
['base16', 'f', base16, '0123456789abcdef'],
['base32hex', 'v', baseX, '0123456789abcdefghijklmnopqrstuv'],
['base32', 'b', baseX, 'abcdefghijklmnopqrstuvwxyz234567'],
['base32z', 'h', baseX, 'ybndrfg8ejkmcpqxot1uwisza345h769'],
['base32', 'b', base32, 'abcdefghijklmnopqrstuvwxyz234567'],
['base32pad', 'c', base32, 'abcdefghijklmnopqrstuvwxyz234567='],
['base32hex', 'v', base32, '0123456789abcdefghijklmnopqrstuv'],
['base32hexpad', 't', base32, '0123456789abcdefghijklmnopqrstuv='],
['base32z', 'h', base32, 'ybndrfg8ejkmcpqxot1uwisza345h769'],
['base58flickr', 'Z', baseX, '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ'],
['base58btc', 'z', baseX, '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'],
['base64', 'm', baseX, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'],
['base64url', 'u', baseX, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_']
['base64', 'm', base64, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'],
['base64pad', 'M', base64, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='],
['base64url', 'u', base64, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'],
['base64urlpad', 'U', base64, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=']
]

const names = constants.reduce((prev, tupple) => {
Expand Down
4 changes: 2 additions & 2 deletions test/constants.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ const constants = require('../src/constants.js')
describe('constants', () => {
it('constants indexed by name', () => {
const names = constants.names
expect(Object.keys(names).length).to.equal(12)
expect(Object.keys(names).length).to.equal(16)
})

it('constants indexed by code', () => {
const codes = constants.codes
expect(Object.keys(codes).length).to.equal(12)
expect(Object.keys(codes).length).to.equal(16)
})
})
64 changes: 62 additions & 2 deletions test/multibase.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,75 @@ const supportedBases = [
['base8', 'yes mani !', '7171312714403326055632220041'],
['base10', 'yes mani !', '9573277761329450583662625'],
['base16', 'yes mani !', 'f796573206d616e692021'],

['base16', new Buffer([0x01]), 'f01'],
['base16', new Buffer([15]), 'f0f'],
['base32hex', 'yes mani !', 'vf5in683dc5n6i811'],
['base16', 'f', 'f66'],
['base16', 'fo', 'f666f'],
['base16', 'foo', 'f666f6f'],
['base16', 'foob', 'f666f6f62'],
['base16', 'fooba', 'f666f6f6261'],
['base16', 'foobar', 'f666f6f626172'],

['base32', 'yes mani !', 'bpfsxgidnmfxgsibb'],
['base32', 'f', 'bmy'],
['base32', 'fo', 'bmzxq'],
['base32', 'foo', 'bmzxw6'],
['base32', 'foob', 'bmzxw6yq'],
['base32', 'fooba', 'bmzxw6ytb'],
['base32', 'foobar', 'bmzxw6ytboi'],

['base32pad', 'yes mani !', 'cpfsxgidnmfxgsibb'],
['base32pad', 'f', 'cmy======'],
['base32pad', 'fo', 'cmzxq===='],
['base32pad', 'foo', 'cmzxw6==='],
['base32pad', 'foob', 'cmzxw6yq='],
['base32pad', 'fooba', 'cmzxw6ytb'],
['base32pad', 'foobar', 'cmzxw6ytboi======'],

['base32hex', 'yes mani !', 'vf5in683dc5n6i811'],
['base32hex', 'f', 'vco'],
['base32hex', 'fo', 'vcpng'],
['base32hex', 'foo', 'vcpnmu'],
['base32hex', 'foob', 'vcpnmuog'],
['base32hex', 'fooba', 'vcpnmuoj1'],
['base32hex', 'foobar', 'vcpnmuoj1e8'],

['base32hexpad', 'yes mani !', 'tf5in683dc5n6i811'],
['base32hexpad', 'f', 'tco======'],
['base32hexpad', 'fo', 'tcpng===='],
['base32hexpad', 'foo', 'tcpnmu==='],
['base32hexpad', 'foob', 'tcpnmuog='],
['base32hexpad', 'fooba', 'tcpnmuoj1'],
['base32hexpad', 'foobar', 'tcpnmuoj1e8======'],

['base32z', 'yes mani !', 'hxf1zgedpcfzg1ebb'],
['base58flickr', 'yes mani !', 'Z7Pznk19XTTzBtx'],
['base58btc', 'yes mani !', 'z7paNL19xttacUY'],

['base64', '÷ïÿ', 'mw7fDr8O/'],
['base64url', '÷ïÿ', 'uw7fDr8O_']
['base64', 'f', 'mZg'],
['base64', 'fo', 'mZm8'],
['base64', 'foo', 'mZm9v'],
['base64', 'foob', 'mZm9vYg'],
['base64', 'fooba', 'mZm9vYmE'],
['base64', 'foobar', 'mZm9vYmFy'],

['base64pad', 'f', 'MZg=='],
['base64pad', 'fo', 'MZm8='],
['base64pad', 'foo', 'MZm9v'],
['base64pad', 'foob', 'MZm9vYg=='],
['base64pad', 'fooba', 'MZm9vYmE='],
['base64pad', 'foobar', 'MZm9vYmFy'],

['base64url', '÷ïÿ', 'uw7fDr8O_'],

['base64urlpad', 'f', 'UZg=='],
['base64urlpad', 'fo', 'UZm8='],
['base64urlpad', 'foo', 'UZm9v'],
['base64urlpad', 'foob', 'UZm9vYg=='],
['base64urlpad', 'fooba', 'UZm9vYmE='],
['base64urlpad', 'foobar', 'UZm9vYmFy']
]

describe('multibase', () => {
Expand Down

0 comments on commit a9b5150

Please sign in to comment.