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
39 changes: 39 additions & 0 deletions lib/buffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ const {
Uint8Array,
} = primordials;

// TODO(LiviaMedeiros): replace with primordial once `--js-base-64` is not optional
// eslint-disable-next-line node-core/prefer-primordials
const { fromHex: Uint8ArrayFromHex, fromBase64: Uint8ArrayFromBase64 } = Uint8Array;

const {
byteLengthUtf8,
compare: _compare,
Expand Down Expand Up @@ -336,6 +340,41 @@ Buffer.from = function from(value, encodingOrOffset, length) {
);
};

// eslint-disable-next-line node-core/prefer-primordials
if (Uint8ArrayFromHex) {
/**
* Same as Uint8Array.fromHex(hexstring), but returns instance of Buffer.
* Not same as Buffer.from(hexstring), as it performs different validations.
* @param {string} str
* @returns {Buffer}
*/
Buffer.fromHex = function fromHex(str) {
const buf = Uint8ArrayFromHex(str);
return fromArrayBuffer(
TypedArrayPrototypeGetBuffer(buf),
TypedArrayPrototypeGetByteOffset(buf),
TypedArrayPrototypeGetByteLength(buf));
};
}

// eslint-disable-next-line node-core/prefer-primordials
if (Uint8ArrayFromBase64) {
/**
* Same as Uint8Array.fromBase64(base64string, options), but returns instance of Buffer.
* @param {string} str
* @param {object} [options]
* @returns {Buffer}
*/
Buffer.fromBase64 = function fromBase64(str, options) {
const buf = Uint8ArrayFromBase64(str, options);
return fromArrayBuffer(
TypedArrayPrototypeGetBuffer(buf),
TypedArrayPrototypeGetByteOffset(buf),
TypedArrayPrototypeGetByteLength(buf));
};
}


/**
* 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'));

Check failure on line 6 in test/parallel/test-buffer-fromhex-frombase64.js

View workflow job for this annotation

GitHub Actions / test-linux (ubuntu-24.04-arm)

--- stderr --- node:internal/assert/utils:146 throw error; ^ AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + actual - expected + Uint8Array(4) [ - Buffer(4) [Uint8Array] [ 240, 13, 202, 254 ] at Object.<anonymous> (/home/runner/work/node/node/node/test/parallel/test-buffer-fromhex-frombase64.js:6:8) at Module._compile (node:internal/modules/cjs/loader:1803:14) at Object..js (node:internal/modules/cjs/loader:1934:10) at Module.load (node:internal/modules/cjs/loader:1524:32) at Module._load (node:internal/modules/cjs/loader:1326:12) at TracingChannel.traceSync (node:diagnostics_channel:328:14) at wrapModuleLoad (node:internal/modules/cjs/loader:245:24) at Module.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:154:5) at node:internal/main/run_main_module:33:47 { generatedMessage: true, code: 'ERR_ASSERTION', actual: Uint8Array(4) [ 240, 13, 202, 254 ], expected: Buffer(4) [Uint8Array] [ 240, 13, 202, 254 ], operator: 'deepStrictEqual', diff: 'simple' } Node.js v26.0.0-pre Command: out/Release/node /home/runner/work/node/node/node/test/parallel/test-buffer-fromhex-frombase64.js

Check failure on line 6 in test/parallel/test-buffer-fromhex-frombase64.js

View workflow job for this annotation

GitHub Actions / test-linux (ubuntu-24.04)

--- stderr --- node:internal/assert/utils:146 throw error; ^ AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + actual - expected + Uint8Array(4) [ - Buffer(4) [Uint8Array] [ 240, 13, 202, 254 ] at Object.<anonymous> (/home/runner/work/node/node/node/test/parallel/test-buffer-fromhex-frombase64.js:6:8) at Module._compile (node:internal/modules/cjs/loader:1803:14) at Object..js (node:internal/modules/cjs/loader:1934:10) at Module.load (node:internal/modules/cjs/loader:1524:32) at Module._load (node:internal/modules/cjs/loader:1326:12) at TracingChannel.traceSync (node:diagnostics_channel:328:14) at wrapModuleLoad (node:internal/modules/cjs/loader:245:24) at Module.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:154:5) at node:internal/main/run_main_module:33:47 { generatedMessage: true, code: 'ERR_ASSERTION', actual: Uint8Array(4) [ 240, 13, 202, 254 ], expected: Buffer(4) [Uint8Array] [ 240, 13, 202, 254 ], operator: 'deepStrictEqual', diff: 'simple' } Node.js v26.0.0-pre Command: out/Release/node /home/runner/work/node/node/node/test/parallel/test-buffer-fromhex-frombase64.js

Check failure on line 6 in test/parallel/test-buffer-fromhex-frombase64.js

View workflow job for this annotation

GitHub Actions / test-macOS

--- stderr --- node:internal/assert/utils:146 throw error; ^ AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + actual - expected + Uint8Array(4) [ - Buffer(4) [Uint8Array] [ 240, 13, 202, 254 ] at Object.<anonymous> (/Users/runner/work/node/node/node/test/parallel/test-buffer-fromhex-frombase64.js:6:8) at Module._compile (node:internal/modules/cjs/loader:1803:14) at Object..js (node:internal/modules/cjs/loader:1934:10) at Module.load (node:internal/modules/cjs/loader:1524:32) at Module._load (node:internal/modules/cjs/loader:1326:12) at TracingChannel.traceSync (node:diagnostics_channel:328:14) at wrapModuleLoad (node:internal/modules/cjs/loader:245:24) at Module.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:154:5) at node:internal/main/run_main_module:33:47 { generatedMessage: true, code: 'ERR_ASSERTION', actual: Uint8Array(4) [ 240, 13, 202, 254 ], expected: Buffer(4) [Uint8Array] [ 240, 13, 202, 254 ], operator: 'deepStrictEqual', diff: 'simple' } Node.js v26.0.0-pre Command: out/Release/node /Users/runner/work/node/node/node/test/parallel/test-buffer-fromhex-frombase64.js

Check failure on line 6 in test/parallel/test-buffer-fromhex-frombase64.js

View workflow job for this annotation

GitHub Actions / aarch64-darwin: with shared libraries

--- stderr --- node:internal/assert/utils:146 throw error; ^ AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + actual - expected + Uint8Array(4) [ - Buffer(4) [Uint8Array] [ 240, 13, 202, 254 ] at Object.<anonymous> (/Users/runner/work/_temp/node-v26.0.0-nightly2026-01-063b1081bacc-slim/test/parallel/test-buffer-fromhex-frombase64.js:6:8) at Module._compile (node:internal/modules/cjs/loader:1803:14) at Object..js (node:internal/modules/cjs/loader:1934:10) at Module.load (node:internal/modules/cjs/loader:1524:32) at Module._load (node:internal/modules/cjs/loader:1326:12) at TracingChannel.traceSync (node:diagnostics_channel:328:14) at wrapModuleLoad (node:internal/modules/cjs/loader:245:24) at Module.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:154:5) at node:internal/main/run_main_module:33:47 { generatedMessage: true, code: 'ERR_ASSERTION', actual: Uint8Array(4) [ 240, 13, 202, 254 ], expected: Buffer(4) [Uint8Array] [ 240, 13, 202, 254 ], operator: 'deepStrictEqual', diff: 'simple' } Node.js v26.0.0-pre Command: out/Release/node /Users/runner/work/_temp/node-v26.0.0-nightly2026-01-063b1081bacc-slim/test/parallel/test-buffer-fromhex-frombase64.js

Check failure on line 6 in test/parallel/test-buffer-fromhex-frombase64.js

View workflow job for this annotation

GitHub Actions / aarch64-linux: with shared libraries

--- stderr --- node:internal/assert/utils:146 throw error; ^ AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + actual - expected + Uint8Array(4) [ - Buffer(4) [Uint8Array] [ 240, 13, 202, 254 ] at Object.<anonymous> (/home/runner/work/_temp/node-v26.0.0-nightly2026-01-063b1081bacc-slim/test/parallel/test-buffer-fromhex-frombase64.js:6:8) at Module._compile (node:internal/modules/cjs/loader:1803:14) at Object..js (node:internal/modules/cjs/loader:1934:10) at Module.load (node:internal/modules/cjs/loader:1524:32) at Module._load (node:internal/modules/cjs/loader:1326:12) at TracingChannel.traceSync (node:diagnostics_channel:328:14) at wrapModuleLoad (node:internal/modules/cjs/loader:245:24) at Module.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:154:5) at node:internal/main/run_main_module:33:47 { generatedMessage: true, code: 'ERR_ASSERTION', actual: Uint8Array(4) [ 240, 13, 202, 254 ], expected: Buffer(4) [Uint8Array] [ 240, 13, 202, 254 ], operator: 'deepStrictEqual', diff: 'simple' } Node.js v26.0.0-pre Command: out/Release/node /home/runner/work/_temp/node-v26.0.0-nightly2026-01-063b1081bacc-slim/test/parallel/test-buffer-fromhex-frombase64.js

Check failure on line 6 in test/parallel/test-buffer-fromhex-frombase64.js

View workflow job for this annotation

GitHub Actions / x86_64-darwin: with shared libraries

--- stderr --- node:internal/assert/utils:146 throw error; ^ AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + actual - expected + Uint8Array(4) [ - Buffer(4) [Uint8Array] [ 240, 13, 202, 254 ] at Object.<anonymous> (/Users/runner/work/_temp/node-v26.0.0-nightly2026-01-063b1081bacc-slim/test/parallel/test-buffer-fromhex-frombase64.js:6:8) at Module._compile (node:internal/modules/cjs/loader:1803:14) at Object..js (node:internal/modules/cjs/loader:1934:10) at Module.load (node:internal/modules/cjs/loader:1524:32) at Module._load (node:internal/modules/cjs/loader:1326:12) at TracingChannel.traceSync (node:diagnostics_channel:328:14) at wrapModuleLoad (node:internal/modules/cjs/loader:245:24) at Module.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:154:5) at node:internal/main/run_main_module:33:47 { generatedMessage: true, code: 'ERR_ASSERTION', actual: Uint8Array(4) [ 240, 13, 202, 254 ], expected: Buffer(4) [Uint8Array] [ 240, 13, 202, 254 ], operator: 'deepStrictEqual', diff: 'simple' } Node.js v26.0.0-pre Command: out/Release/node /Users/runner/work/_temp/node-v26.0.0-nightly2026-01-063b1081bacc-slim/test/parallel/test-buffer-fromhex-frombase64.js

Check failure on line 6 in test/parallel/test-buffer-fromhex-frombase64.js

View workflow job for this annotation

GitHub Actions / x86_64-linux: with shared libraries

--- stderr --- node:internal/assert/utils:146 throw error; ^ AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + actual - expected + Uint8Array(4) [ - Buffer(4) [Uint8Array] [ 240, 13, 202, 254 ] at Object.<anonymous> (/home/runner/work/_temp/node-v26.0.0-nightly2026-01-063b1081bacc-slim/test/parallel/test-buffer-fromhex-frombase64.js:6:8) at Module._compile (node:internal/modules/cjs/loader:1803:14) at Object..js (node:internal/modules/cjs/loader:1934:10) at Module.load (node:internal/modules/cjs/loader:1524:32) at Module._load (node:internal/modules/cjs/loader:1326:12) at TracingChannel.traceSync (node:diagnostics_channel:328:14) at wrapModuleLoad (node:internal/modules/cjs/loader:245:24) at Module.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:154:5) at node:internal/main/run_main_module:33:47 { generatedMessage: true, code: 'ERR_ASSERTION', actual: Uint8Array(4) [ 240, 13, 202, 254 ], expected: Buffer(4) [Uint8Array] [ 240, 13, 202, 254 ], operator: 'deepStrictEqual', diff: 'simple' } Node.js v26.0.0-pre Command: out/Release/node /home/runner/work/_temp/node-v26.0.0-nightly2026-01-063b1081bacc-slim/test/parallel/test-buffer-fromhex-frombase64.js
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