url_sanitizer.mjs 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. /**
  2. * @license
  3. * SPDX-License-Identifier: Apache-2.0
  4. */
  5. /**
  6. * @fileoverview Provides functions to enforce the SafeUrl contract at the sink
  7. * level.
  8. */
  9. import '../environment/dev';
  10. function extractScheme(url) {
  11. let parsedUrl;
  12. try {
  13. parsedUrl = new URL(url);
  14. }
  15. catch (e) {
  16. // According to https://url.spec.whatwg.org/#constructors, the URL
  17. // constructor with one parameter throws if `url` is not absolute. In this
  18. // case, we are sure that no explicit scheme (javascript: ) is set.
  19. // This can also be a URL parsing error, but in this case the URL won't be
  20. // run anyway.
  21. return 'https:';
  22. }
  23. return parsedUrl.protocol;
  24. }
  25. // We can't use an ES6 Set here because gws somehow depends on this code and
  26. // doesn't want to pay the cost of a polyfill.
  27. const ALLOWED_SCHEMES = ['data:', 'http:', 'https:', 'mailto:', 'ftp:'];
  28. /**
  29. * Checks that the URL scheme is not javascript.
  30. * The URL parsing relies on the URL API in browsers that support it.
  31. * @param url The URL to sanitize for a SafeUrl sink.
  32. * @return undefined if url has a javascript: scheme, the original URL
  33. * otherwise.
  34. */
  35. export function sanitizeJavascriptUrl(url) {
  36. const parsedScheme = extractScheme(url);
  37. if (parsedScheme === 'javascript:') {
  38. if (process.env.NODE_ENV !== 'production') {
  39. console.error(`A URL with content '${url}' was sanitized away.`);
  40. }
  41. return undefined;
  42. }
  43. return url;
  44. }
  45. /**
  46. * Adapter to sanitize string URLs in DOM sink wrappers.
  47. * @return undefined if the URL was sanitized.
  48. */
  49. export function unwrapUrlOrSanitize(url) {
  50. return sanitizeJavascriptUrl(url);
  51. }
  52. /**
  53. * Sanitizes a URL restrictively.
  54. * This sanitizer protects against XSS and potentially other uncommon and
  55. * undesirable schemes that an attacker could use for e.g. phishing (tel:,
  56. * callto: ssh: etc schemes). This sanitizer is primarily meant to be used by
  57. * the HTML sanitizer.
  58. */
  59. export function restrictivelySanitizeUrl(url) {
  60. const parsedScheme = extractScheme(url);
  61. if (parsedScheme !== undefined &&
  62. ALLOWED_SCHEMES.indexOf(parsedScheme.toLowerCase()) !== -1) {
  63. return url;
  64. }
  65. return 'about:invalid#zClosurez';
  66. }