Browse Source

refactor: use Reflect.apply, Reflect.has

tophf 3 years ago
parent
commit
6a0e59504a

+ 1 - 1
scripts/webpack-protect-bootstrap-plugin.js

@@ -26,7 +26,7 @@ const BOOTSTRAP_RULES = [
     G.definePropertyGetters,
   ], [
     'Object.prototype.hasOwnProperty.call(',
-    'safeCall(hasOwnProperty, ',
+    'hasOwnProperty(',
     G.hasOwnProperty,
   ],
 ];

+ 1 - 1
src/background/index.js

@@ -71,7 +71,7 @@ const commandsToSyncIfTruthy = [
 ];
 
 async function handleCommandMessage({ cmd, data } = {}, src) {
-  const func = commands::hasOwnProperty(cmd) && commands[cmd];
+  const func = hasOwnProperty(commands, cmd) && commands[cmd];
   if (!func) {
     throw new SafeError(`Unknown command: ${cmd}`);
   }

+ 1 - 1
src/background/utils/options.js

@@ -96,7 +96,7 @@ export function setOption(key, value, silent) {
   const keys = normalizeKeys(key);
   const mainKey = keys[0];
   key = keys.join('.'); // must be a string for addChange()
-  if (!defaults::hasOwnProperty(mainKey)) {
+  if (!hasOwnProperty(defaults, mainKey)) {
     if (process.env.DEBUG) console.info('Unknown option:', key, value, options);
     return;
   }

+ 1 - 1
src/background/utils/preinject.js

@@ -149,7 +149,7 @@ async function removeStaleCacheEntry(val, key) {
 }
 
 function normalizeRealm(value) {
-  return INJECT_MAPPING::hasOwnProperty(value)
+  return hasOwnProperty(INJECT_MAPPING, value)
     ? value
     : injectInto || INJECT_AUTO;
 }

+ 1 - 1
src/background/utils/storage-cache.js

@@ -58,7 +58,7 @@ storage.api = {
         cache.put(key, deepCopy(val), !keys && TTL_SKIM);
         updateScriptMap(key, val);
       });
-      keys?.forEach(key => dbKeys.put(key, +res::hasOwnProperty(key)));
+      keys?.forEach(key => dbKeys.put(key, +hasOwnProperty(res, key)));
     }
     batch(false);
     return res;

+ 5 - 5
src/common/browser.js

@@ -5,7 +5,7 @@
 if (!IS_FIREFOX && !global.browser?.runtime) {
   // region Chrome
   const { chrome, Proxy: SafeProxy } = global;
-  const { apply, bind } = SafeProxy;
+  const { bind } = SafeProxy;
   const MESSAGE = 'message';
   const STACK = 'stack';
   const isSyncMethodName = key => key === 'addListener'
@@ -20,7 +20,7 @@ if (!IS_FIREFOX && !global.browser?.runtime) {
     if (isFunction(metaVal)) {
       res = metaVal(src, srcVal);
     } else if (isFunction(srcVal)) {
-      res = metaVal === 0 || isSyncMethodName(key) || !src::hasOwnProperty(key)
+      res = metaVal === 0 || isSyncMethodName(key) || !hasOwnProperty(src, key)
         ? srcVal::bind(src)
         : wrapAsync(src, srcVal); // eslint-disable-line no-use-before-define
     } else if (isObject(srcVal) && metaVal !== 0) {
@@ -70,7 +70,7 @@ if (!IS_FIREFOX && !global.browser?.runtime) {
       };
       if (process.env.IS_INJECTED) {
         try {
-          func::apply(thisArg, args);
+          safeApply(func, thisArg, args);
         } catch (e) {
           if (e[MESSAGE] === 'Extension context invalidated.') {
             console.error(`Please reload the tab to restore ${VIOLENTMONKEY} API for userscripts.`);
@@ -79,7 +79,7 @@ if (!IS_FIREFOX && !global.browser?.runtime) {
           }
         }
       } else {
-        func::apply(thisArg, args);
+        safeApply(func, thisArg, args);
       }
       if (process.env.DEBUG) promise.catch(err => console.warn(args, err?.[MESSAGE] || err));
       return promise;
@@ -110,7 +110,7 @@ if (!IS_FIREFOX && !global.browser?.runtime) {
     if (process.env.DEBUG) console.info('receive', message);
     try {
       const result = listener(message, sender);
-      if (result && result::objectToString() === '[object Promise]') {
+      if (result && isFunction(result.then)) {
         sendResponseAsync(result, sendResponse);
         return true;
       }

+ 1 - 1
src/common/date.js

@@ -57,7 +57,7 @@ export function formatDate(tpl, date = new Date()) {
     }`, 'g');
   }
   return tpl.replace(re, (s, literal) => (
-    DATE_FMT::hasOwnProperty(s)
+    hasOwnProperty(DATE_FMT, s)
       ? DATE_FMT[s](date)
       : literal ?? s
   ));

+ 1 - 1
src/common/safe-globals.js

@@ -21,7 +21,7 @@ const {
 } = global;
 export const SafePromise = Promise; // alias used by browser.js
 export const SafeError = Error; // alias used by browser.js
-export const { hasOwnProperty, toString: objectToString } = {};
+export const { apply: safeApply, has: hasOwnProperty } = Reflect;
 export const safeCall = Object.call.bind(Object.call);
 export const IS_FIREFOX = !global.chrome.app;
 export const isFunction = val => typeof val === 'function';

+ 1 - 1
src/common/util.js

@@ -206,7 +206,7 @@ export function formatByteLength(len, noBytes) {
 // Used by `injected`
 export function isEmpty(obj) {
   for (const key in obj) {
-    if (obj::hasOwnProperty(key)) {
+    if (hasOwnProperty(obj, key)) {
       return false;
     }
   }

+ 1 - 1
src/injected/content/inject.js

@@ -256,7 +256,7 @@ function inject(item, iframeCb) {
       : div
   );
   if (isCodeArray) {
-    append::apply(script, code);
+    safeApply(append, script, code);
   }
   let iframe;
   let iframeDoc;

+ 2 - 3
src/injected/content/safe-globals-content.js

@@ -24,9 +24,8 @@ export const {
 export const SafeError = Error;
 export const PromiseProto = SafePromise[PROTO];
 export const ResponseProto = SafeResponse[PROTO];
-export const { hasOwnProperty, toString: objectToString } = {};
-export const { apply, call } = hasOwnProperty;
-export const safeCall = call.bind(call);
+export const { apply: safeApply, has: hasOwnProperty } = Reflect;
+export const safeCall = safeApply.call.bind(safeApply.call);
 export const { forEach, includes } = []; // `push` is unsafe as it may call a setter; use safePush()
 export const { createElementNS, getElementsByTagName } = document;
 export const { then } = SafePromise[PROTO];

+ 3 - 3
src/injected/safe-globals-injected.js

@@ -33,7 +33,7 @@ export const isString = val => typeof val === 'string';
 export const getOwnProp = (obj, key, defVal) => {
   // obj may be a Proxy that throws in has() or its getter throws
   try {
-    if (obj::hasOwnProperty(key)) defVal = obj[key];
+    if (hasOwnProperty(obj, key)) defVal = obj[key];
   } catch (e) { /* NOP */ }
   return defVal;
 };
@@ -58,7 +58,7 @@ export const pickIntoNullObj = (dst, src, keys) => {
   if (process.env.DEBUG) throwIfProtoPresent(dst);
   if (src) {
     keys::forEach(key => {
-      if (src::hasOwnProperty(key)) {
+      if (hasOwnProperty(src, key)) {
         dst[key] = src[key];
       }
     });
@@ -111,7 +111,7 @@ export const log = (level, ...args) => {
   let s = `[${VIOLENTMONKEY}]`;
   if (args[0]) args[0]::forEach(tag => { s += `[${tag}]`; });
   args[0] = s;
-  logging[level]::apply(logging, args);
+  safeApply(logging[level], logging, args);
 };
 
 /**

+ 1 - 1
src/injected/web/gm-global-wrapper.js

@@ -119,7 +119,7 @@ function makeOwnKeys(local, globals) {
    * on `push` and `arr[i] = 123`, as well as via getters if you read beyond
    * its length or from an unassigned `hole`. */
   const frameIndexes = [];
-  for (let i = 0, len = window::getWindowLength(); i < len && window::hasOwnProperty(i); i += 1) {
+  for (let i = 0, len = window::getWindowLength(); i < len && hasOwnProperty(window, i); i += 1) {
     if (!(i in local)) {
       setOwnProp(frameIndexes, i, i);
     }

+ 6 - 11
src/injected/web/safe-globals-web.js

@@ -32,16 +32,12 @@ export let
   // Symbol
   toStringTagSym,
   // Object
-  apply,
   assign,
   defineProperty,
   describeProperty,
   getPrototypeOf,
   objectKeys,
   objectValues,
-  // Object.prototype
-  hasOwnProperty,
-  objectToString,
   /** Array.prototype can be eavesdropped via setters like '0','1',...
    * on `push` and `arr[i] = 123`, as well as via getters if you read beyond
    * its length or from an unassigned `hole`. */
@@ -55,6 +51,7 @@ export let
   charCodeAt,
   slice,
   // safeCall
+  safeApply,
   safeBind,
   safeCall,
   // various values
@@ -64,7 +61,7 @@ export let
   arrayIsArray,
   createObjectURL,
   formDataEntries,
-  funcToString,
+  hasOwnProperty,
   jsonParse,
   jsonStringify,
   logging,
@@ -85,6 +82,7 @@ export let
  * or window[0] before our content script runs at document_start, https://crbug.com/1261964 */
 export const VAULT = (() => {
   let ArrayP;
+  let Reflect;
   let SafeObject;
   let StringP;
   let i = -1;
@@ -130,10 +128,6 @@ export const VAULT = (() => {
     assign = res[i += 1] || SafeObject.assign,
     objectKeys = res[i += 1] || SafeObject.keys,
     objectValues = res[i += 1] || SafeObject.values,
-    apply = res[i += 1] || SafeObject.apply,
-    // Object.prototype
-    hasOwnProperty = res[i += 1] || SafeObject[PROTO].hasOwnProperty,
-    objectToString = res[i += 1] || SafeObject[PROTO].toString,
     // Array.prototype
     concat = res[i += 1] || (ArrayP = src.Array[PROTO]).concat,
     filter = res[i += 1] || ArrayP.filter,
@@ -145,13 +139,14 @@ export const VAULT = (() => {
     charCodeAt = res[i += 1] || (StringP = src.String[PROTO]).charCodeAt,
     slice = res[i += 1] || StringP.slice,
     // safeCall
+    safeApply = res[i += 1] || (Reflect = src.Reflect).apply,
     safeCall = res[i += 1] || (call = SafeObject.call).bind(call),
     safeBind = res[i += 1] || call.bind(SafeObject.bind),
     // various methods
     URLToString = res[i += 1] || src.URL[PROTO].toString,
     createObjectURL = res[i += 1] || src.URL.createObjectURL,
     formDataEntries = res[i += 1] || src.FormData[PROTO].entries,
-    funcToString = res[i += 1] || safeCall.toString,
+    hasOwnProperty = res[i += 1] || Reflect.has,
     arrayIsArray = res[i += 1] || src.Array.isArray,
     /* Exporting JSON methods separately instead of exporting SafeJSON as its props may be broken
      * by the page if it gains access to any Object from the vault e.g. a thrown SafeError. */
@@ -160,7 +155,7 @@ export const VAULT = (() => {
     logging = res[i += 1] || createNullObj((srcFF || src).console),
     mathRandom = res[i += 1] || src.Math.random,
     parseFromString = res[i += 1] || SafeDOMParser[PROTO].parseFromString,
-    reflectOwnKeys = res[i += 1] || src.Reflect.ownKeys,
+    reflectOwnKeys = res[i += 1] || Reflect.ownKeys,
     stopImmediatePropagation = res[i += 1] || src.Event[PROTO].stopImmediatePropagation,
     then = res[i += 1] || src.Promise[PROTO].then,
     // various getters

+ 2 - 2
src/injected/web/util.js

@@ -7,7 +7,7 @@ export const safeConcat = (...arrays) => {
   setOwnProp(dest, isConcatSpreadableSym, true);
   arrays::forEach(arr => setOwnProp(arr, isConcatSpreadableSym, true));
   // Using a dummy [] is simpler/safer/faster than (getOwnProp(arrays, 0), arrays::slice(1))
-  return concat::apply(dest, arrays);
+  return safeApply(concat, dest, arrays);
 };
 
 /**
@@ -72,7 +72,7 @@ export const FastLookup = (hubs = createNullObj()) => {
     toArray: () => {
       const values = objectValues(hubs);
       values::forEach((val, i) => { values[i] = objectKeys(val); });
-      return safeConcat::apply(null, values);
+      return safeApply(safeConcat, null, values);
     },
   };
   function getHub(key, autoCreate) {

+ 1 - 1
src/options/views/tab-settings/index.vue

@@ -206,7 +206,7 @@ const items = {
   ...badgeColorEnum::mapEntry(() => badgeColorItem),
 };
 const normalizeEnum = (value, name) => (
-  items[name].enum::hasOwnProperty(value)
+  hasOwnProperty(items[name].enum, value)
     ? value
     : Object.keys(items[name].enum)[0]
 );