diff --git a/src/package.ts b/src/package.ts index eeee356a..4ed19827 100644 --- a/src/package.ts +++ b/src/package.ts @@ -772,7 +772,7 @@ export class MarkdownProcessor extends BaseProcessor { contents = contents.replace(markdownPathRegex, urlReplace); // Replace links with urls - contents = contents.replace(//g, (all, link) => { + contents = contents.replace(/]+src=["']([/.\w\s#-]+)['"][^>]*>/gm, (all, link) => { const isLinkRelative = !/^\w+:\/\//.test(link) && link[0] !== '#'; if (!this.baseImagesUrl && isLinkRelative) { @@ -840,7 +840,13 @@ export class MarkdownProcessor extends BaseProcessor { } const src = decodeURI(rawSrc); - const srcUrl = new url.URL(src); + let srcUrl: url.URL + + try { + srcUrl = new url.URL(src); + } catch (err) { + throw new Error(`Invalid image source in ${this.name}: ${src}`); + } if (/^data:$/i.test(srcUrl.protocol) && /^image$/i.test(srcUrl.host) && /\/svg/i.test(srcUrl.pathname)) { throw new Error(`SVG data URLs are not allowed in ${this.name}: ${src}`); @@ -1273,7 +1279,13 @@ export function validateManifest(manifest: Manifest): Manifest { (manifest.badges ?? []).forEach(badge => { const decodedUrl = decodeURI(badge.url); - const srcUrl = new url.URL(decodedUrl); + let srcUrl: url.URL; + + try { + srcUrl = new url.URL(decodedUrl); + } catch (err) { + throw new Error(`Badge URL is invalid: ${badge.url}`); + } if (!/^https:$/i.test(srcUrl.protocol)) { throw new Error(`Badge URLs must come from an HTTPS source: ${badge.url}`); diff --git a/src/test/package.test.ts b/src/test/package.test.ts index 2dfddce2..e4c599b6 100644 --- a/src/test/package.test.ts +++ b/src/test/package.test.ts @@ -2896,6 +2896,22 @@ describe('MarkdownProcessor', () => { await throws(() => processor.onFile(readme)); }); + it('should allow img tags spanning across lines, issue #904', async () => { + const manifest = { + name: 'test', + publisher: 'mocha', + version: '0.0.1', + engines: Object.create(null), + repository: 'https://github.com/username/repository', + }; + const contents = ``; + const processor = new ReadmeProcessor(manifest, {}); + const readme = { path: 'extension/readme.md', contents }; + + const file = await processor.onFile(readme); + assert.ok(file); + }); + it('should catch an unchanged README.md', async () => { const manifest = { name: 'test',