mirror of
https://github.com/ChromeDevTools/chrome-devtools-mcp.git
synced 2026-09-14 19:45:30 +08:00
feat: extend --no-javascript-evaluation to cover navigations and initScripts (#2638)
This commit is contained in:
@@ -181,7 +181,7 @@ The Chrome DevTools MCP server supports the following configuration option:
|
||||
- **Default:** `true`
|
||||
|
||||
- **`--javascriptEvaluation`/ `--javascript-evaluation`**
|
||||
Set to false to disable tools to evaluate JavaScript scripts.
|
||||
Set to false to disable JavaScript execution. When disabled, evaluation tools (evaluate_script and slim evaluate) are disabled, the initScript parameter in navigate_page is turned off, and navigating to javascript:, data:, or vbscript: URLs is disallowed.
|
||||
- **Type:** boolean
|
||||
- **Default:** `true`
|
||||
|
||||
|
||||
@@ -300,7 +300,8 @@ export const mcpOptions = {
|
||||
javascriptEvaluation: {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
describe: 'Set to false to disable tools to evaluate JavaScript scripts.',
|
||||
describe:
|
||||
'Set to false to disable JavaScript execution. When disabled, evaluation tools (evaluate_script and slim evaluate) are disabled, the initScript parameter in navigate_page is turned off, and navigating to javascript:, data:, or vbscript: URLs is disallowed.',
|
||||
},
|
||||
clearcutEndpoint: {
|
||||
type: 'string',
|
||||
@@ -562,7 +563,7 @@ export function parser(
|
||||
],
|
||||
[
|
||||
'$0 --no-javascript-evaluation',
|
||||
'Disable tools to evaluate JavaScript scripts.',
|
||||
'Disable JavaScript execution (disables evaluation tools, initScript in navigate_page, and navigating to javascript:, data:, or vbscript: URLs).',
|
||||
],
|
||||
[
|
||||
'$0 --slim',
|
||||
|
||||
+19
-8
@@ -7,6 +7,7 @@
|
||||
import type {CdpPage} from '../third_party/index.js';
|
||||
import {zod} from '../third_party/index.js';
|
||||
import {logger} from '../utils/logger.js';
|
||||
import {validateUrl} from '../utils/url.js';
|
||||
|
||||
import {ToolCategory} from './categories.js';
|
||||
import {
|
||||
@@ -96,7 +97,7 @@ export const closePage = defineTool({
|
||||
},
|
||||
});
|
||||
|
||||
export const newPage = defineTool(() => {
|
||||
export const newPage = defineTool(args => {
|
||||
return {
|
||||
name: 'new_page',
|
||||
description: `Open a new tab and load a URL. Use project URL if not specified otherwise.`,
|
||||
@@ -125,6 +126,8 @@ export const newPage = defineTool(() => {
|
||||
blockedByDialog: false,
|
||||
verifyFilesSchema: {},
|
||||
handler: async (request, response, context) => {
|
||||
validateUrl(request.params.url, args?.javascriptEvaluation);
|
||||
|
||||
const page = await context.newPage(
|
||||
request.params.background,
|
||||
request.params.isolatedContext,
|
||||
@@ -145,7 +148,7 @@ export const newPage = defineTool(() => {
|
||||
};
|
||||
});
|
||||
|
||||
export const navigatePage = definePageTool(() => {
|
||||
export const navigatePage = definePageTool(args => {
|
||||
return {
|
||||
name: 'navigate_page',
|
||||
description: `Go to a URL, or back, forward, or reload. Use project URL if not specified otherwise.`,
|
||||
@@ -171,12 +174,16 @@ export const navigatePage = definePageTool(() => {
|
||||
.describe(
|
||||
'Whether to auto accept or beforeunload dialogs triggered by this navigation. Default is accept.',
|
||||
),
|
||||
initScript: zod
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
'A JavaScript script to be executed on each new document before any other scripts for the next navigation.',
|
||||
),
|
||||
...(args?.javascriptEvaluation !== false
|
||||
? {
|
||||
initScript: zod
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
'A JavaScript script to be executed on each new document before any other scripts for the next navigation.',
|
||||
),
|
||||
}
|
||||
: {}),
|
||||
...timeoutSchema,
|
||||
},
|
||||
blockedByDialog: false,
|
||||
@@ -195,6 +202,10 @@ export const navigatePage = definePageTool(() => {
|
||||
request.params.type = 'url';
|
||||
}
|
||||
|
||||
if (request.params.url) {
|
||||
validateUrl(request.params.url, args?.javascriptEvaluation);
|
||||
}
|
||||
|
||||
let initScriptId: string | undefined;
|
||||
if (request.params.initScript) {
|
||||
const {identifier} = await page.pptrPage.evaluateOnNewDocument(
|
||||
|
||||
+39
-34
@@ -8,6 +8,7 @@ import type {Dialog} from '../../third_party/index.js';
|
||||
import {zod} from '../../third_party/index.js';
|
||||
import {ToolCategory} from '../categories.js';
|
||||
import {definePageTool} from '../ToolDefinition.js';
|
||||
import {validateUrl} from '../../utils/url.js';
|
||||
|
||||
export const screenshot = definePageTool({
|
||||
name: 'screenshot',
|
||||
@@ -34,43 +35,47 @@ export const screenshot = definePageTool({
|
||||
},
|
||||
});
|
||||
|
||||
export const navigate = definePageTool({
|
||||
name: 'navigate',
|
||||
description: `Loads a URL`,
|
||||
annotations: {
|
||||
category: ToolCategory.NAVIGATION,
|
||||
readOnlyHint: false,
|
||||
},
|
||||
schema: {
|
||||
url: zod.string().describe('URL to navigate to'),
|
||||
},
|
||||
blockedByDialog: false,
|
||||
verifyFilesSchema: {},
|
||||
handler: async (request, response) => {
|
||||
const page = request.page;
|
||||
export const navigate = definePageTool(args => {
|
||||
return {
|
||||
name: 'navigate',
|
||||
description: `Loads a URL`,
|
||||
annotations: {
|
||||
category: ToolCategory.NAVIGATION,
|
||||
readOnlyHint: false,
|
||||
},
|
||||
schema: {
|
||||
url: zod.string().describe('URL to navigate to'),
|
||||
},
|
||||
blockedByDialog: false,
|
||||
verifyFilesSchema: {},
|
||||
handler: async (request, response) => {
|
||||
validateUrl(request.params.url, args?.javascriptEvaluation);
|
||||
|
||||
const options = {
|
||||
timeout: 30_000,
|
||||
};
|
||||
const page = request.page;
|
||||
|
||||
const dialogHandler = (dialog: Dialog) => {
|
||||
if (dialog.type() === 'beforeunload') {
|
||||
response.appendResponseLine(`Accepted a beforeunload dialog.`);
|
||||
void dialog.accept();
|
||||
// We are not going to report the dialog like regular dialogs.
|
||||
page.clearDialog();
|
||||
const options = {
|
||||
timeout: 30_000,
|
||||
};
|
||||
|
||||
const dialogHandler = (dialog: Dialog) => {
|
||||
if (dialog.type() === 'beforeunload') {
|
||||
response.appendResponseLine(`Accepted a beforeunload dialog.`);
|
||||
void dialog.accept();
|
||||
// We are not going to report the dialog like regular dialogs.
|
||||
page.clearDialog();
|
||||
}
|
||||
};
|
||||
|
||||
page.pptrPage.on('dialog', dialogHandler);
|
||||
|
||||
try {
|
||||
await page.pptrPage.goto(request.params.url, options);
|
||||
response.appendResponseLine(`Navigated to ${page.pptrPage.url()}.`);
|
||||
} finally {
|
||||
page.pptrPage.off('dialog', dialogHandler);
|
||||
}
|
||||
};
|
||||
|
||||
page.pptrPage.on('dialog', dialogHandler);
|
||||
|
||||
try {
|
||||
await page.pptrPage.goto(request.params.url, options);
|
||||
response.appendResponseLine(`Navigated to ${page.pptrPage.url()}.`);
|
||||
} finally {
|
||||
page.pptrPage.off('dialog', dialogHandler);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
export const evaluate = definePageTool({
|
||||
|
||||
@@ -48,3 +48,35 @@ export function isLocalhost(url?: string): boolean {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const DISALLOWED_PROTOCOLS = new Set(['javascript:', 'data:', 'vbscript:']);
|
||||
|
||||
/**
|
||||
* Validates a URL string by parsing it with `new URL` and checking for disallowed protocols.
|
||||
*
|
||||
* @param url The URL string to validate.
|
||||
* @param javascriptEvaluation Whether JavaScript evaluation is enabled.
|
||||
* @returns The parsed URL.
|
||||
* @throws Error if the URL does not parse with `new URL`, or if JavaScript evaluation is disabled and a disallowed URL is passed.
|
||||
*/
|
||||
export function validateUrl(url: string, javascriptEvaluation?: boolean): URL {
|
||||
let parsed: URL;
|
||||
try {
|
||||
parsed = new URL(url);
|
||||
} catch {
|
||||
throw new Error(
|
||||
`Invalid URL: "${url}". URLs must be valid according to the URL standard.`,
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
javascriptEvaluation === false &&
|
||||
DISALLOWED_PROTOCOLS.has(parsed.protocol)
|
||||
) {
|
||||
throw new Error(
|
||||
`Navigating to ${parsed.protocol} URLs is not allowed when JavaScript evaluation is disabled.`,
|
||||
);
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
@@ -124,6 +124,30 @@ describe('chrome-devtools', () => {
|
||||
),
|
||||
'restart command suggestion is missing: ' + result.stdout,
|
||||
);
|
||||
|
||||
const navResult = await runCli(
|
||||
['navigate_page', '1', '--url', 'javascript:alert(1)'],
|
||||
sessionId,
|
||||
);
|
||||
assert.strictEqual(navResult.status, 0);
|
||||
assert(
|
||||
navResult.stdout.includes(
|
||||
'Navigating to javascript: URLs is not allowed when JavaScript evaluation is disabled.',
|
||||
),
|
||||
'error message is unexpected: ' + navResult.stdout,
|
||||
);
|
||||
|
||||
const initScriptResult = await runCli(
|
||||
['navigate_page', '1', '--initScript', 'alert(1)'],
|
||||
sessionId,
|
||||
);
|
||||
assert.strictEqual(initScriptResult.status, 0);
|
||||
assert(
|
||||
initScriptResult.stdout.includes(
|
||||
'Unknown argument for tool "navigate_page": "initScript"',
|
||||
),
|
||||
'error message is unexpected: ' + initScriptResult.stdout,
|
||||
);
|
||||
});
|
||||
|
||||
it('can record a performance trace', async () => {
|
||||
|
||||
+173
-1
@@ -11,7 +11,10 @@ import {afterEach, describe, it} from 'node:test';
|
||||
import type {Dialog} from 'puppeteer-core';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import type {ParsedArguments} from '../../src/config/mcp-options.js';
|
||||
import {
|
||||
parseArguments,
|
||||
type ParsedArguments,
|
||||
} from '../../src/config/mcp-options.js';
|
||||
import {
|
||||
listPages,
|
||||
newPage,
|
||||
@@ -249,6 +252,73 @@ describe('pages', () => {
|
||||
assert.ok(response.includePages);
|
||||
});
|
||||
});
|
||||
it('throws when navigating to a javascript URL and javascriptEvaluation is false', async () => {
|
||||
await withMcpContext(async (response, context) => {
|
||||
const disabledArgs = parseArguments(
|
||||
'1.0.0',
|
||||
['node', 'script.js', '--no-javascript-evaluation'],
|
||||
{CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS: 'true'},
|
||||
);
|
||||
const tool = newPage(disabledArgs);
|
||||
await assert.rejects(
|
||||
async () => {
|
||||
await tool.handler(
|
||||
{params: {url: 'javascript:alert(1)'}},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
},
|
||||
{
|
||||
message:
|
||||
'Navigating to javascript: URLs is not allowed when JavaScript evaluation is disabled.',
|
||||
},
|
||||
);
|
||||
await assert.rejects(
|
||||
async () => {
|
||||
await tool.handler(
|
||||
{params: {url: 'data:text/html,<div>test</div>'}},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
},
|
||||
{
|
||||
message:
|
||||
'Navigating to data: URLs is not allowed when JavaScript evaluation is disabled.',
|
||||
},
|
||||
);
|
||||
await assert.rejects(
|
||||
async () => {
|
||||
await tool.handler(
|
||||
{params: {url: 'vbscript:msgbox(1)'}},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
},
|
||||
{
|
||||
message:
|
||||
'Navigating to vbscript: URLs is not allowed when JavaScript evaluation is disabled.',
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
it('throws when URL does not parse with new URL', async () => {
|
||||
await withMcpContext(async (response, context) => {
|
||||
const tool = newPage();
|
||||
await assert.rejects(
|
||||
async () => {
|
||||
await tool.handler(
|
||||
{params: {url: 'not a valid url'}},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
},
|
||||
{
|
||||
message:
|
||||
'Invalid URL: "not a valid url". URLs must be valid according to the URL standard.',
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
it('create a page in the background', async () => {
|
||||
await withMcpContext(async (response, context) => {
|
||||
const originalPage = context.getPageById(1);
|
||||
@@ -917,6 +987,108 @@ describe('pages', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('omits initScript from schema when javascriptEvaluation is false', () => {
|
||||
const defaultTool = navigatePage();
|
||||
assert.strictEqual('initScript' in defaultTool.schema, true);
|
||||
|
||||
const disabledArgs = parseArguments(
|
||||
'1.0.0',
|
||||
['node', 'script.js', '--no-javascript-evaluation'],
|
||||
{CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS: 'true'},
|
||||
);
|
||||
const disabledTool = navigatePage(disabledArgs);
|
||||
assert.strictEqual('initScript' in disabledTool.schema, false);
|
||||
});
|
||||
|
||||
it('throws when navigating to a javascript, data, or vbscript URL and javascriptEvaluation is false', async () => {
|
||||
await withMcpContext(async (response, context) => {
|
||||
const disabledArgs = parseArguments(
|
||||
'1.0.0',
|
||||
['node', 'script.js', '--no-javascript-evaluation'],
|
||||
{CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS: 'true'},
|
||||
);
|
||||
const tool = navigatePage(disabledArgs);
|
||||
await assert.rejects(
|
||||
async () => {
|
||||
await tool.handler(
|
||||
{
|
||||
params: {
|
||||
url: 'javascript:alert(1)',
|
||||
},
|
||||
page: context.getSelectedMcpPage(),
|
||||
},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
},
|
||||
{
|
||||
message:
|
||||
'Navigating to javascript: URLs is not allowed when JavaScript evaluation is disabled.',
|
||||
},
|
||||
);
|
||||
await assert.rejects(
|
||||
async () => {
|
||||
await tool.handler(
|
||||
{
|
||||
params: {
|
||||
url: 'data:text/html,<div>test</div>',
|
||||
},
|
||||
page: context.getSelectedMcpPage(),
|
||||
},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
},
|
||||
{
|
||||
message:
|
||||
'Navigating to data: URLs is not allowed when JavaScript evaluation is disabled.',
|
||||
},
|
||||
);
|
||||
await assert.rejects(
|
||||
async () => {
|
||||
await tool.handler(
|
||||
{
|
||||
params: {
|
||||
url: 'vbscript:msgbox(1)',
|
||||
},
|
||||
page: context.getSelectedMcpPage(),
|
||||
},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
},
|
||||
{
|
||||
message:
|
||||
'Navigating to vbscript: URLs is not allowed when JavaScript evaluation is disabled.',
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('throws when URL does not parse with new URL', async () => {
|
||||
await withMcpContext(async (response, context) => {
|
||||
const tool = navigatePage();
|
||||
await assert.rejects(
|
||||
async () => {
|
||||
await tool.handler(
|
||||
{
|
||||
params: {
|
||||
url: 'not a valid url',
|
||||
},
|
||||
page: context.getSelectedMcpPage(),
|
||||
},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
},
|
||||
{
|
||||
message:
|
||||
'Invalid URL: "not a valid url". URLs must be valid according to the URL standard.',
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('when dialog is open', async t => {
|
||||
await withMcpContext(async (response, context) => {
|
||||
const page = context.getSelectedMcpPage().pptrPage;
|
||||
|
||||
@@ -9,6 +9,7 @@ import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import {describe, it} from 'node:test';
|
||||
|
||||
import {parseArguments} from '../../../src/config/mcp-options.js';
|
||||
import {evaluate, navigate, screenshot} from '../../../src/tools/slim/tools.js';
|
||||
import {screenshots} from '../../snapshot.js';
|
||||
import {withMcpContext} from '../../utils.js';
|
||||
@@ -48,7 +49,7 @@ describe('slim', () => {
|
||||
|
||||
it('navigates to correct page', async t => {
|
||||
await withMcpContext(async (response, context) => {
|
||||
await navigate.handler(
|
||||
await navigate().handler(
|
||||
{
|
||||
params: {url: 'data:text/html,<div>Hello MCP</div>'},
|
||||
page: context.getSelectedMcpPage(),
|
||||
@@ -66,6 +67,86 @@ describe('slim', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('throws when URL does not parse with new URL', async () => {
|
||||
await withMcpContext(async (response, context) => {
|
||||
await assert.rejects(
|
||||
async () => {
|
||||
await navigate().handler(
|
||||
{
|
||||
params: {url: 'not a valid url'},
|
||||
page: context.getSelectedMcpPage(),
|
||||
},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
},
|
||||
{
|
||||
message:
|
||||
'Invalid URL: "not a valid url". URLs must be valid according to the URL standard.',
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('disallows javascript, data, and vbscript URLs when javascriptEvaluation is false', async () => {
|
||||
await withMcpContext(async (response, context) => {
|
||||
const disabledArgs = parseArguments(
|
||||
'1.0.0',
|
||||
['node', 'script.js', '--slim', '--no-javascript-evaluation'],
|
||||
{CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS: 'true'},
|
||||
);
|
||||
const tool = navigate(disabledArgs);
|
||||
await assert.rejects(
|
||||
async () => {
|
||||
await tool.handler(
|
||||
{
|
||||
params: {url: 'javascript:alert(1)'},
|
||||
page: context.getSelectedMcpPage(),
|
||||
},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
},
|
||||
{
|
||||
message:
|
||||
'Navigating to javascript: URLs is not allowed when JavaScript evaluation is disabled.',
|
||||
},
|
||||
);
|
||||
await assert.rejects(
|
||||
async () => {
|
||||
await tool.handler(
|
||||
{
|
||||
params: {url: 'data:text/html,<div>test</div>'},
|
||||
page: context.getSelectedMcpPage(),
|
||||
},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
},
|
||||
{
|
||||
message:
|
||||
'Navigating to data: URLs is not allowed when JavaScript evaluation is disabled.',
|
||||
},
|
||||
);
|
||||
await assert.rejects(
|
||||
async () => {
|
||||
await tool.handler(
|
||||
{
|
||||
params: {url: 'vbscript:msgbox(1)'},
|
||||
page: context.getSelectedMcpPage(),
|
||||
},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
},
|
||||
{
|
||||
message:
|
||||
'Navigating to vbscript: URLs is not allowed when JavaScript evaluation is disabled.',
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('with default options', async () => {
|
||||
await withMcpContext(async (response, context) => {
|
||||
const fixture = screenshots.basic;
|
||||
|
||||
+81
-1
@@ -7,7 +7,7 @@
|
||||
import assert from 'node:assert';
|
||||
import {describe, it} from 'node:test';
|
||||
|
||||
import {isLocalhost} from '../../src/utils/url.js';
|
||||
import {isLocalhost, validateUrl} from '../../src/utils/url.js';
|
||||
|
||||
describe('isLocalhost', () => {
|
||||
it('should return true for valid localhost and loopback URLs', () => {
|
||||
@@ -87,3 +87,83 @@ describe('isLocalhost', () => {
|
||||
assert.strictEqual(isLocalhost('not a url'), false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('validateUrl', () => {
|
||||
it('should return URL object for valid URLs', () => {
|
||||
assert.strictEqual(
|
||||
validateUrl('https://example.com').href,
|
||||
'https://example.com/',
|
||||
);
|
||||
assert.strictEqual(
|
||||
validateUrl('http://localhost:3000').href,
|
||||
'http://localhost:3000/',
|
||||
);
|
||||
assert.strictEqual(validateUrl('about:blank').href, 'about:blank');
|
||||
assert.strictEqual(
|
||||
validateUrl('data:text/html,<div>test</div>').href,
|
||||
'data:text/html,<div>test</div>',
|
||||
);
|
||||
});
|
||||
|
||||
it('should reject URLs that do not parse with new URL', () => {
|
||||
assert.throws(() => validateUrl('not a url'), /Invalid URL: "not a url"/);
|
||||
assert.throws(() => validateUrl(''), /Invalid URL: ""/);
|
||||
assert.throws(() => validateUrl('http://'), /Invalid URL: "http:\/\/"/);
|
||||
assert.throws(() => validateUrl('://'), /Invalid URL: ":\/\/"/);
|
||||
});
|
||||
|
||||
it('should allow javascript, data, and vbscript URLs when javascriptEvaluation is true or omitted', () => {
|
||||
assert.strictEqual(
|
||||
validateUrl('javascript:alert(1)').protocol,
|
||||
'javascript:',
|
||||
);
|
||||
assert.strictEqual(
|
||||
validateUrl('javascript:alert(1)', true).protocol,
|
||||
'javascript:',
|
||||
);
|
||||
assert.strictEqual(
|
||||
validateUrl('data:text/html,<div>test</div>').protocol,
|
||||
'data:',
|
||||
);
|
||||
assert.strictEqual(
|
||||
validateUrl('data:text/html,<div>test</div>', true).protocol,
|
||||
'data:',
|
||||
);
|
||||
assert.strictEqual(validateUrl('vbscript:msgbox(1)').protocol, 'vbscript:');
|
||||
assert.strictEqual(
|
||||
validateUrl('vbscript:msgbox(1)', true).protocol,
|
||||
'vbscript:',
|
||||
);
|
||||
});
|
||||
|
||||
it('should reject javascript, data, and vbscript URLs when javascriptEvaluation is false', () => {
|
||||
assert.throws(
|
||||
() => validateUrl('javascript:alert(1)', false),
|
||||
/Navigating to javascript: URLs is not allowed when JavaScript evaluation is disabled\./,
|
||||
);
|
||||
assert.throws(
|
||||
() => validateUrl('JAVASCRIPT:alert(1)', false),
|
||||
/Navigating to javascript: URLs is not allowed when JavaScript evaluation is disabled\./,
|
||||
);
|
||||
assert.throws(
|
||||
() => validateUrl('javascript:void(0)', false),
|
||||
/Navigating to javascript: URLs is not allowed when JavaScript evaluation is disabled\./,
|
||||
);
|
||||
assert.throws(
|
||||
() => validateUrl('data:text/html,<div>test</div>', false),
|
||||
/Navigating to data: URLs is not allowed when JavaScript evaluation is disabled\./,
|
||||
);
|
||||
assert.throws(
|
||||
() => validateUrl('DATA:text/html,<div>test</div>', false),
|
||||
/Navigating to data: URLs is not allowed when JavaScript evaluation is disabled\./,
|
||||
);
|
||||
assert.throws(
|
||||
() => validateUrl('vbscript:msgbox(1)', false),
|
||||
/Navigating to vbscript: URLs is not allowed when JavaScript evaluation is disabled\./,
|
||||
);
|
||||
assert.throws(
|
||||
() => validateUrl('VBSCRIPT:msgbox(1)', false),
|
||||
/Navigating to vbscript: URLs is not allowed when JavaScript evaluation is disabled\./,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user