Skip to content
Open
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
35 changes: 35 additions & 0 deletions doc/api/buffer.md
Original file line number Diff line number Diff line change
Expand Up @@ -1419,6 +1419,39 @@ appropriate for `Buffer.from()` variants.
[`Buffer.from(string)`][] may also use the internal `Buffer` pool like
[`Buffer.allocUnsafe()`][] does.

### Static method: `Buffer.fromBase64(base64string[, options])`

<!-- YAML
added: REPLACEME
-->

* `base64string` {string} A base64 string to decode.
* `options` {Object}
* `alphabet` {string} One of `'base64'` (default) or `'base64url'`.
* `lastChunkHandling` {string} One of `'loose'` (default), `'strict'`, or `'stop-before-partial'`.
* Returns: {Buffer}

This static method is same as [`Uint8Array.fromBase64()`][], except it
returns `Buffer` rather than `Uint8Array`.

This is not exactly the same as `Buffer.from(base64string, 'base64')`,
and this function will throw `SyntaxError` if input contains non-base64 symbols.

### Static method: `Buffer.fromHex(string)`

<!-- YAML
added: REPLACEME
-->

* `string` {string} A hexadecimal string to decode.
* Returns: {Buffer}

This static method is same as [`Uint8Array.fromHex()`][], except it
returns `Buffer` rather than `Uint8Array`.

This is not exactly the same as `Buffer.from(hexstring, 'hex')`,
and this function will throw `SyntaxError` if input contains non-hex symbols.

### Static method: `Buffer.isBuffer(obj)`

<!-- YAML
Expand Down Expand Up @@ -5540,6 +5573,8 @@ introducing security vulnerabilities into an application.
[`TypedArray.prototype.set()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/set
[`TypedArray.prototype.slice()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/slice
[`TypedArray.prototype.subarray()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/subarray
[`Uint8Array.fromBase64()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array/fromBase64
[`Uint8Array.fromHex()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array/fromBase64
[`buf.buffer`]: #bufbuffer
[`buf.compare()`]: #bufcomparetarget-targetstart-targetend-sourcestart-sourceend
[`buf.entries()`]: #bufentries
Expand Down
76 changes: 76 additions & 0 deletions lib/buffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,82 @@ Buffer.from = function from(value, encodingOrOffset, length) {
);
};

/**
* Same as Uint8Array.fromHex(hexstring), but returns instance of Buffer.
* Not same as Buffer.from(hexstring), as it performs different validations.
* @function Buffer.fromHex
* @param {string} str
* @returns {Buffer}
*/
ObjectDefineProperty(Buffer, 'fromHex', {
__proto__: null,
configurable: true,
enumerable: false,
get() {
// TODO(LiviaMedeiros): make unconditional and use primordial once `--js-base-64` is not optional
// eslint-disable-next-line node-core/prefer-primordials
const Uint8ArrayFromHex = Uint8Array.fromHex;
const value = Uint8ArrayFromHex === undefined ?
undefined :
function fromHex(str) {
const buf = Uint8ArrayFromHex(str);
return fromArrayBuffer(
TypedArrayPrototypeGetBuffer(buf),
TypedArrayPrototypeGetByteOffset(buf),
TypedArrayPrototypeGetByteLength(buf),
);
};

ObjectDefineProperty(Buffer, 'fromHex', {
__proto__: null,
value,
configurable: true,
enumerable: false,
writable: true,
});

return value;
},
});

/**
* Same as Uint8Array.fromBase64(base64string, options), but returns instance of Buffer.
* @function Buffer.fromBase64
* @param {string} str
* @param {object} [options]
* @returns {Buffer}
*/
ObjectDefineProperty(Buffer, 'fromBase64', {
__proto__: null,
configurable: true,
enumerable: false,
get() {
// TODO(LiviaMedeiros): make unconditional and use primordial once `--js-base-64` is not optional
// eslint-disable-next-line node-core/prefer-primordials
const Uint8ArrayFromBase64 = Uint8Array.fromBase64;
const value = Uint8ArrayFromBase64 === undefined ?
undefined :
function fromBase64(str, options) {
const buf = Uint8ArrayFromBase64(str, options);
return fromArrayBuffer(
TypedArrayPrototypeGetBuffer(buf),
TypedArrayPrototypeGetByteOffset(buf),
TypedArrayPrototypeGetByteLength(buf),
);
};

ObjectDefineProperty(Buffer, 'fromBase64', {
__proto__: null,
value,
configurable: true,
enumerable: false,
writable: true,
});

return value;
},
});

/**
* Creates the Buffer as a copy of the underlying ArrayBuffer of the view
* rather than the contents of the view.
Expand Down
34 changes: 34 additions & 0 deletions test/parallel/test-buffer-fromhex-frombase64.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
'use strict';
require('../common');
const assert = require('assert');
const { Buffer } = require('buffer');

assert.deepStrictEqual(Buffer.fromHex('f00dcafe'), Buffer.from('f00dcafe', 'hex'));
assert.deepStrictEqual(Buffer.fromHex('F00DCAFE'), Buffer.from('f00dcafe', 'hex'));
assert.deepStrictEqual(Buffer.fromHex(''), Buffer.from('', 'hex'));

assert.throws(() => Buffer.fromHex('0x'), { name: 'SyntaxError' });
assert.throws(() => Buffer.fromHex('a'), { name: 'SyntaxError' });
assert.throws(() => Buffer.fromHex(123), { name: 'TypeError' });
assert.throws(() => Buffer.fromHex('abggcd00'), { name: 'SyntaxError' });

assert.deepStrictEqual(Buffer.fromBase64('SGVsbG8='), Buffer.from('SGVsbG8=', 'base64'));
assert.deepStrictEqual(Buffer.fromBase64('SGV sbG8='), Buffer.from('SGVsbG8=', 'base64'));

assert.deepStrictEqual(
Buffer.fromBase64('PGJsZXA-PC9ibGVwPg', { alphabet: 'base64url' }),
Buffer.from('PGJsZXA+PC9ibGVwPg==', 'base64'),
);

assert.deepStrictEqual(Buffer.fromBase64('SGVsbG8=', { lastChunkHandling: 'strict' }), Buffer.from('Hello'));
assert.throws(() => Buffer.fromBase64('SGVsbG8', { lastChunkHandling: 'strict' }), { name: 'SyntaxError' });

assert.deepStrictEqual(
Buffer.fromBase64('SGVsbG8', { lastChunkHandling: 'stop-before-partial' }),
Buffer.from('SGVs', 'base64'),
);

assert.throws(() => Buffer.fromBase64('SGV$sbG8=', {}), { name: 'SyntaxError' });
assert.throws(() => Buffer.fromBase64('S', {}), { name: 'SyntaxError' });
assert.throws(() => Buffer.fromBase64(123), { name: 'TypeError' });
assert.throws(() => Buffer.fromBase64('SGVsbG8=', { alphabet: 'unknown' }), { name: 'TypeError' });
Loading