Преглед изворни кода

fix: allow data: in script deps

tophf пре 3 година
родитељ
комит
396cda6807
4 измењених фајлова са 29 додато и 12 уклоњено
  1. 8 3
      src/background/utils/db.js
  2. 1 0
      src/background/utils/storage-fetch.js
  3. 9 8
      src/common/ui/externals.vue
  4. 11 1
      src/common/util.js

+ 8 - 3
src/background/utils/db.js

@@ -1,5 +1,6 @@
 import {
-  compareVersion, i18n, getFullUrl, getScriptName, isRemote, sendCmd, trueJoin,
+  compareVersion, dataUri2text, i18n,
+  getFullUrl, getScriptName, isRemote, sendCmd, trueJoin,
 } from '#/common';
 import { INJECT_PAGE, INJECT_AUTO, TIMEOUT_WEEK } from '#/common/consts';
 import { forEachEntry, forEachKey, forEachValue } from '#/common/object';
@@ -348,14 +349,18 @@ async function readEnvironmentData(env, isRetry) {
   const keys = [];
   STORAGE_ROUTES.forEach(([area, srcIds]) => {
     env[srcIds].forEach(id => {
-      keys.push(storage[area].getKey(id));
+      if (!/^data:/.test(id)) {
+        keys.push(storage[area].getKey(id));
+      }
     });
   });
   const data = await storage.base.getMulti(keys);
   for (const [area, srcIds] of STORAGE_ROUTES) {
     env[area] = {};
     for (const id of env[srcIds]) {
-      const val = data[storage[area].getKey(id)];
+      const val = /^data:/.test(id)
+        ? area !== 'require' && id || dataUri2text(id)
+        : data[storage[area].getKey(id)];
       env[area][id] = val;
       if (val == null && area !== 'value' && retriedStorageKeys[area + id] !== 2) {
         const err = `The "${area}" storage is missing "${id}"!`;

+ 1 - 0
src/background/utils/storage-fetch.js

@@ -35,6 +35,7 @@ function cacheOrFetch(handlers = {}) {
   async function doFetch(...args) {
     const [url, options] = args;
     try {
+      if (url.startsWith('data:')) return;
       const res = await request(url, init?.(options) || options);
       if (await isModified(res, url)) {
         const result = transform ? await transform(res, ...args) : res.data;

+ 9 - 8
src/common/ui/externals.vue

@@ -34,7 +34,7 @@
 </template>
 
 <script>
-import { formatByteLength, string2uint8array } from '#/common';
+import { formatByteLength, dataUri2text } from '#/common';
 import VmCode from '#/common/ui/code';
 import storage from '#/common/storage';
 
@@ -67,7 +67,8 @@ export default {
       if (!url) return;
       const { install } = this;
       const isMain = install && !index;
-      const isReq = !isMain && type === '@require';
+      const isDataUri = url.startsWith('data:');
+      const isReq = !isMain && !isDataUri && type === '@require';
       const depsUrl = `${+!isReq}${url}`;
       let code;
       let contentType;
@@ -76,7 +77,9 @@ export default {
       if (isMain) {
         code = install.code;
       } else {
-        if (install) {
+        if (isDataUri) {
+          raw = url;
+        } else if (install) {
           raw = install.deps[depsUrl];
         } else {
           const key = this.value.custom.pathMap?.[url] || url;
@@ -94,12 +97,10 @@ export default {
             contentType = /^(png|jpe?g|bmp|svgz?|gz|zip)$/i.test(fileExt)
               ? ''
               : `text/${fileExt.toLowerCase()}`;
-            code = raw;
-          }
-          code = atob(code);
-          if (/[\x80-\xFF]/.test(code)) {
-            code = new TextDecoder().decode(string2uint8array(code));
+          } else if (contentType) {
+            contentType = contentType.split(/[:;]/)[1];
           }
+          code = dataUri2text(raw);
         }
       }
       this.img = img;

+ 11 - 1
src/common/util.js

@@ -121,6 +121,16 @@ export function blob2base64(blob, offset = 0, length = 1e99) {
   });
 }
 
+export function dataUri2text(url) {
+  const i = url.indexOf(','); // a non-base64 data: uri may have many `,`
+  const meta = url.slice(0, i);
+  url = decodeURIComponent(url.slice(i + 1));
+  url = /(^|;)\s*base64\s*(;|$)/.test(meta) ? atob(url) : url;
+  return /[\x80-\xFF]/.test(url)
+    ? new TextDecoder().decode(string2uint8array(url))
+    : url;
+}
+
 export function string2uint8array(str) {
   const len = str.length;
   const array = new Uint8Array(len);
@@ -272,7 +282,7 @@ export async function request(url, options = {}) {
   if (url.startsWith('file://')) return requestLocalFile(url, options);
   const { body, headers, responseType } = options;
   const isBodyObj = body && body::({}).toString() === '[object Object]';
-  const [, scheme, auth, hostname, urlTail] = url.match(/^([-\w]+:\/\/)([^@/]*@)?([^/]*)(.*)/);
+  const [, scheme, auth, hostname, urlTail] = url.match(/^([-\w]+:\/\/)([^@/]*@)?([^/]*)(.*)|$/);
   const accept = FORCED_ACCEPT[hostname];
   // Not using ...spread because Babel mistakenly adds its polyfill to injected-web
   const init = Object.assign({