diff --git a/src/core/obj.js b/src/core/obj.js index bbbfe232c..c8a564c7e 100644 --- a/src/core/obj.js +++ b/src/core/obj.js @@ -48,7 +48,7 @@ var shadow = sharedUtil.shadow; var stringToPDFString = sharedUtil.stringToPDFString; var stringToUTF8String = sharedUtil.stringToUTF8String; var warn = sharedUtil.warn; -var isValidUrl = sharedUtil.isValidUrl; +var createValidAbsoluteUrl = sharedUtil.createValidAbsoluteUrl; var Util = sharedUtil.Util; var Ref = corePrimitives.Ref; var RefSet = corePrimitives.RefSet; @@ -694,13 +694,9 @@ var Catalog = (function CatalogClosure() { if (isString(url)) { url = tryConvertUrlEncoding(url); - var absoluteUrl; - try { - absoluteUrl = new URL(url).href; - } catch (ex) { /* `new URL()` will throw on incorrect data. */ } - - if (isValidUrl(absoluteUrl, /* allowRelative = */ false)) { - resultObj.url = absoluteUrl; + var absoluteUrl = createValidAbsoluteUrl(url); + if (absoluteUrl) { + resultObj.url = absoluteUrl.href; } resultObj.unsafeUrl = url; } diff --git a/src/display/dom_utils.js b/src/display/dom_utils.js index a41eda2f8..5894bf4d1 100644 --- a/src/display/dom_utils.js +++ b/src/display/dom_utils.js @@ -28,6 +28,8 @@ var removeNullCharacters = sharedUtil.removeNullCharacters; var warn = sharedUtil.warn; +var deprecated = sharedUtil.deprecated; +var createValidAbsoluteUrl = sharedUtil.createValidAbsoluteUrl; /** * Optimised CSS custom property getter/setter. @@ -229,9 +231,16 @@ function isExternalLinkTargetSet() { } } +function isValidUrl(url, allowRelative) { + deprecated('isValidUrl(), please use createValidAbsoluteUrl() instead.'); + var baseUrl = allowRelative ? 'http://example.com' : null; + return createValidAbsoluteUrl(url, baseUrl) !== null; +} + exports.CustomStyle = CustomStyle; exports.addLinkAttributes = addLinkAttributes; exports.isExternalLinkTargetSet = isExternalLinkTargetSet; +exports.isValidUrl = isValidUrl; exports.getFilenameFromUrl = getFilenameFromUrl; exports.LinkTarget = LinkTarget; exports.hasCanvasTypedArrays = hasCanvasTypedArrays; diff --git a/src/display/global.js b/src/display/global.js index 04c451ab4..c5f9f23eb 100644 --- a/src/display/global.js +++ b/src/display/global.js @@ -76,7 +76,7 @@ PDFJS.VERBOSITY_LEVELS = sharedUtil.VERBOSITY_LEVELS; PDFJS.OPS = sharedUtil.OPS; PDFJS.UNSUPPORTED_FEATURES = sharedUtil.UNSUPPORTED_FEATURES; - PDFJS.isValidUrl = sharedUtil.isValidUrl; + PDFJS.isValidUrl = displayDOMUtils.isValidUrl; PDFJS.shadow = sharedUtil.shadow; PDFJS.createBlob = sharedUtil.createBlob; PDFJS.createObjectURL = function PDFJS_createObjectURL(data, contentType) { diff --git a/src/main_loader.js b/src/main_loader.js index e6dc4920e..a1660908d 100644 --- a/src/main_loader.js +++ b/src/main_loader.js @@ -55,12 +55,12 @@ exports.UnexpectedResponseException = sharedUtil.UnexpectedResponseException; exports.OPS = sharedUtil.OPS; exports.UNSUPPORTED_FEATURES = sharedUtil.UNSUPPORTED_FEATURES; - exports.isValidUrl = sharedUtil.isValidUrl; + exports.isValidUrl = displayDOMUtils.isValidUrl; + exports.createValidAbsoluteUrl = sharedUtil.createValidAbsoluteUrl; exports.createObjectURL = sharedUtil.createObjectURL; exports.removeNullCharacters = sharedUtil.removeNullCharacters; exports.shadow = sharedUtil.shadow; exports.createBlob = sharedUtil.createBlob; exports.getFilenameFromUrl = displayDOMUtils.getFilenameFromUrl; exports.addLinkAttributes = displayDOMUtils.addLinkAttributes; - })); diff --git a/src/pdf.js b/src/pdf.js index 941920320..0322f8b2a 100644 --- a/src/pdf.js +++ b/src/pdf.js @@ -64,7 +64,9 @@ exports.OPS = pdfjsLibs.pdfjsSharedUtil.OPS; exports.UNSUPPORTED_FEATURES = pdfjsLibs.pdfjsSharedUtil.UNSUPPORTED_FEATURES; - exports.isValidUrl = pdfjsLibs.pdfjsSharedUtil.isValidUrl; + exports.isValidUrl = pdfjsLibs.pdfjsDisplayDOMUtils.isValidUrl; + exports.createValidAbsoluteUrl = + pdfjsLibs.pdfjsSharedUtil.createValidAbsoluteUrl; exports.createObjectURL = pdfjsLibs.pdfjsSharedUtil.createObjectURL; exports.removeNullCharacters = pdfjsLibs.pdfjsSharedUtil.removeNullCharacters; diff --git a/src/shared/util.js b/src/shared/util.js index a9554fca7..de33f2be9 100644 --- a/src/shared/util.js +++ b/src/shared/util.js @@ -332,30 +332,42 @@ function isSameOrigin(baseUrl, otherUrl) { return base.origin === other.origin; } -// Validates if URL is safe and allowed, e.g. to avoid XSS. -function isValidUrl(url, allowRelative) { - if (!url || typeof url !== 'string') { +// Checks if URLs use one of the whitelisted protocols, e.g. to avoid XSS. +function isValidProtocol(url) { + if (!url) { return false; } - // RFC 3986 (http://tools.ietf.org/html/rfc3986#section-3.1) - // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) - var protocol = /^[a-z][a-z0-9+\-.]*(?=:)/i.exec(url); - if (!protocol) { - return allowRelative; - } - protocol = protocol[0].toLowerCase(); - switch (protocol) { - case 'http': - case 'https': - case 'ftp': - case 'mailto': - case 'tel': + switch (url.protocol) { + case 'http:': + case 'https:': + case 'ftp:': + case 'mailto:': + case 'tel:': return true; default: return false; } } +/** + * Attempts to create a valid absolute URL (utilizing `isValidProtocol`). + * @param {URL|string} url - An absolute, or relative, URL. + * @param {URL|string} baseUrl - An absolute URL. + * @returns Either a valid {URL}, or `null` otherwise. + */ +function createValidAbsoluteUrl(url, baseUrl) { + if (!url) { + return null; + } + try { + var absoluteUrl = baseUrl ? new URL(url, baseUrl) : new URL(url); + if (isValidProtocol(absoluteUrl)) { + return absoluteUrl; + } + } catch (ex) { /* `new URL()` will throw on incorrect data. */ } + return null; +} + function shadow(obj, prop, value) { Object.defineProperty(obj, prop, { value: value, enumerable: true, @@ -2431,7 +2443,7 @@ exports.isNum = isNum; exports.isString = isString; exports.isSpace = isSpace; exports.isSameOrigin = isSameOrigin; -exports.isValidUrl = isValidUrl; +exports.createValidAbsoluteUrl = createValidAbsoluteUrl; exports.isLittleEndian = isLittleEndian; exports.isEvalSupported = isEvalSupported; exports.loadJpegStream = loadJpegStream; diff --git a/web/download_manager.js b/web/download_manager.js index e58f046c1..75c151038 100644 --- a/web/download_manager.js +++ b/web/download_manager.js @@ -67,10 +67,9 @@ if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC || CHROME')) { DownloadManager.prototype = { downloadUrl: function DownloadManager_downloadUrl(url, filename) { - if (!pdfjsLib.isValidUrl(url, true)) { + if (!pdfjsLib.createValidAbsoluteUrl(url, 'http://example.com')) { return; // restricted/invalid URL } - download(url + '#pdfjs.action=download', filename); },