1
0

single-file.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. /*
  2. * Copyright 2010-2019 Gildas Lormeau
  3. * contact : gildas.lormeau <at> gmail.com
  4. *
  5. * This file is part of SingleFile.
  6. *
  7. * The code in this file is free software: you can redistribute it and/or
  8. * modify it under the terms of the GNU Affero General Public License
  9. * (GNU AGPL) as published by the Free Software Foundation, either version 3
  10. * of the License, or (at your option) any later version.
  11. *
  12. * The code in this file is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
  15. * General Public License for more details.
  16. *
  17. * As additional permission under GNU AGPL version 3 section 7, you may
  18. * distribute UNMODIFIED VERSIONS OF THIS file without the copy of the GNU
  19. * AGPL normally required by section 4, provided you include this license
  20. * notice and a URL through which recipients can access the Corresponding
  21. * Source.
  22. */
  23. /* global
  24. crypto,
  25. fetch,
  26. setTimeout,
  27. Blob,
  28. FileReader,
  29. FontFace,
  30. TextDecoder,
  31. TextEncoder */
  32. this.singlefile.lib.SingleFile = this.singlefile.lib.SingleFile || (() => {
  33. const singlefile = this.singlefile;
  34. const FONT_FACE_TEST_MAX_DELAY = 1000;
  35. const modules = {
  36. helper: singlefile.lib.helper,
  37. srcsetParser: singlefile.lib.vendor.srcsetParser,
  38. cssMinifier: singlefile.lib.vendor.cssMinifier,
  39. htmlMinifier: singlefile.lib.modules.htmlMinifier,
  40. serializer: singlefile.lib.modules.serializer,
  41. fontsMinifier: singlefile.lib.modules.fontsMinifier,
  42. fontsAltMinifier: singlefile.lib.modules.fontsAltMinifier,
  43. cssRulesMinifier: singlefile.lib.modules.cssRulesMinifier,
  44. matchedRules: singlefile.lib.modules.matchedRules,
  45. mediasAltMinifier: singlefile.lib.modules.mediasAltMinifier,
  46. imagesAltMinifier: singlefile.lib.modules.imagesAltMinifier
  47. };
  48. const util = {
  49. getResourceContent,
  50. isValidFontUrl,
  51. digestText
  52. };
  53. const SingleFile = singlefile.lib.core.getClass(singlefile.lib.util.getInstance(modules, util), singlefile.lib.vendor.cssTree);
  54. const fetchResource = (singlefile.lib.fetch.content.resources && singlefile.lib.fetch.content.resources.fetch) || fetch;
  55. return {
  56. getClass: () => SingleFile
  57. };
  58. async function getResourceContent(resourceURL, options) {
  59. const resourceContent = await fetchResource(resourceURL, {
  60. referrerPolicy: options.referrerPolicy,
  61. credentials: options.credentials
  62. });
  63. const buffer = await resourceContent.arrayBuffer();
  64. return {
  65. getUrl() {
  66. return resourceContent.url || resourceURL;
  67. },
  68. getContentType() {
  69. return resourceContent.headers && resourceContent.headers.get("content-type");
  70. },
  71. getStatusCode() {
  72. return resourceContent.status;
  73. },
  74. getSize() {
  75. return buffer.byteLength;
  76. },
  77. getText(charset) {
  78. return new TextDecoder(charset).decode(buffer);
  79. },
  80. async getDataUri(contentType) {
  81. const reader = new FileReader();
  82. reader.readAsDataURL(new Blob([buffer], { type: contentType || this.getContentType() }));
  83. return new Promise((resolve, reject) => {
  84. reader.addEventListener("load", () => resolve(reader.result), false);
  85. reader.addEventListener("error", reject, false);
  86. });
  87. }
  88. };
  89. }
  90. async function digestText(algo, text) {
  91. const hash = await crypto.subtle.digest(algo, new TextEncoder("utf-8").encode(text));
  92. return hex(hash);
  93. }
  94. // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest
  95. function hex(buffer) {
  96. const hexCodes = [];
  97. const view = new DataView(buffer);
  98. for (let i = 0; i < view.byteLength; i += 4) {
  99. const value = view.getUint32(i);
  100. const stringValue = value.toString(16);
  101. const padding = "00000000";
  102. const paddedValue = (padding + stringValue).slice(-padding.length);
  103. hexCodes.push(paddedValue);
  104. }
  105. return hexCodes.join("");
  106. }
  107. async function isValidFontUrl(urlFunction) {
  108. try {
  109. const font = new FontFace("font-test", urlFunction);
  110. await Promise.race([font.load(), new Promise(resolve => setTimeout(() => resolve(true), FONT_FACE_TEST_MAX_DELAY))]);
  111. return true;
  112. } catch (error) {
  113. return false;
  114. }
  115. }
  116. })();