Skip to content
Merged
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: 9 additions & 26 deletions lib/internal/webstorage.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
'use strict';
const {
ObjectDefineProperties,
Proxy,
} = primordials;
const { getOptionValue } = require('internal/options');
const { lazyDOMException } = require('internal/util');
const { kConstructorKey, Storage } = internalBinding('webstorage');
const { getValidatedPath } = require('internal/fs/utils');
const kInMemoryPath = ':memory:';
Expand All @@ -21,34 +21,17 @@ ObjectDefineProperties(module.exports, {
enumerable: true,
get() {
if (lazyLocalStorage === undefined) {
// For consistency with the web specification, throw from the accessor
// if the local storage path is not provided.
const location = getOptionValue('--localstorage-file');

if (location === '') {
let warningEmitted = false;
const handler = {
__proto__: null,
get(target, prop) {
if (!warningEmitted) {
process.emitWarning('`--localstorage-file` was provided without a valid path');
warningEmitted = true;
}

return undefined;
},
set(target, prop, value) {
if (!warningEmitted) {
process.emitWarning('`--localstorage-file` was provided without a valid path');
warningEmitted = true;
}

return false;
},
};

lazyLocalStorage = new Proxy({}, handler);
} else {
lazyLocalStorage = new Storage(kConstructorKey, getValidatedPath(location));
throw lazyDOMException(
'Cannot initialize local storage without a `--localstorage-file` path',
'SecurityError',
);
}

lazyLocalStorage = new Storage(kConstructorKey, getValidatedPath(location));
}

return lazyLocalStorage;
Expand Down
19 changes: 18 additions & 1 deletion test/common/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@ const hasSQLite = Boolean(process.versions.sqlite);

const hasQuic = hasCrypto && !!process.features.quic;

const hasLocalStorage = (() => {
try {
return hasSQLite && globalThis.localStorage !== undefined;
} catch {
return false;
}
})();

/**
* Parse test metadata from the specified file.
* @param {string} filename - The name of the file to parse.
Expand Down Expand Up @@ -350,7 +358,6 @@ const knownGlobals = new Set([
'CompressionStream',
'DecompressionStream',
'Storage',
'localStorage',
'sessionStorage',
].forEach((i) => {
if (globalThis[i] !== undefined) {
Expand All @@ -365,6 +372,10 @@ if (hasCrypto) {
knownGlobals.add(globalThis.SubtleCrypto);
}

if (hasLocalStorage) {
knownGlobals.add(globalThis.localStorage);
}

const { Worker } = require('node:worker_threads');
knownGlobals.add(Worker);

Expand All @@ -389,6 +400,11 @@ if (process.env.NODE_TEST_KNOWN_GLOBALS !== '0') {
if (val === 'crypto' && !hasCrypto) {
continue;
}
// globalThis.localStorage is a getter that throws if Node.js was
// executed without a --localstorage-file path.
if (val === 'localStorage' && !hasLocalStorage) {
continue;
}
if (!knownGlobals.has(globalThis[val])) {
leaked.push(val);
}
Expand Down Expand Up @@ -933,6 +949,7 @@ const common = {
hasQuic,
hasInspector,
hasSQLite,
hasLocalStorage,
invalidArgTypeHelper,
isAlive,
isASan,
Expand Down
2 changes: 2 additions & 0 deletions test/common/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const {
hasQuic,
hasInspector,
hasSQLite,
hasLocalStorage,
hasIntl,
hasIPv6,
isAIX,
Expand Down Expand Up @@ -71,6 +72,7 @@ export {
hasQuic,
hasInspector,
hasSQLite,
hasLocalStorage,
hasIntl,
hasIPv6,
isAIX,
Expand Down
4 changes: 2 additions & 2 deletions test/parallel/test-assert-checktag.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
'use strict';
const { hasCrypto } = require('../common');
const { hasCrypto, hasLocalStorage } = require('../common');
const { test } = require('node:test');
const assert = require('assert');

Expand All @@ -12,7 +12,7 @@ const assert = require('assert');
if (process.stdout.isTTY)
process.env.NODE_DISABLE_COLORS = '1';

test('', { skip: !hasCrypto }, () => {
test({ skip: !hasCrypto || !hasLocalStorage }, () => {
// See https://github.com/nodejs/node/issues/10258
{
const date = new Date('2016');
Expand Down
8 changes: 4 additions & 4 deletions test/parallel/test-webstorage.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,13 @@ test('sessionStorage is not persisted', async () => {
assert.strictEqual((await readdir(tmpdir.path)).length, 0);
});

test('localStorage emits a warning when used without --localstorage-file ', async () => {
test('localStorage throws without --localstorage-file', async () => {
const cp = await spawnPromisified(process.execPath, [
'-pe', 'localStorage.length',
'-e', 'localStorage',
]);
assert.strictEqual(cp.code, 0);
assert.strictEqual(cp.code, 1);
assert.strictEqual(cp.signal, null);
assert.match(cp.stderr, /Warning: `--localstorage-file` was provided without a valid path/);
assert.match(cp.stderr, /SecurityError:/);
});

test('localStorage is not persisted if it is unused', async () => {
Expand Down
Loading