Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

个别网页有问题 #150

Closed
1217965058 opened this issue Jun 5, 2020 · 4 comments
Closed

个别网页有问题 #150

1217965058 opened this issue Jun 5, 2020 · 4 comments

Comments

@1217965058
Copy link

1217965058 commented Jun 5, 2020

比如这个页面
参考了#75
发现没有CSP,有define变量,AMD还是CMD什么的我也不懂,在引入eruda前把define设为undefined后,eruda能载入,但有bug
具体问题为:
1️⃣点击图标打不开面板,图标无法拖动。虽然可通过在地址栏输入javascript:eruda.show()打开面板,但后续使用过程中还是有各种各样的问题。
2️⃣无法载入插件。

关于问题1️⃣,在打开面板后拖动或点击图标,console会不停输出错误信息

null at n.value (https://cdn.jsdelivr.net/npm/eruda:27:169394)
at new n (https://cdn.jsdelivr.net/npm/eruda:27:166369)
at r.value (https://cdn.jsdelivr.net/npm/eruda:27:183272)
at https://cdn.jsdelivr.net/npm/eruda:27:185290
at n (https://storage.360buyimg.com/tower/babelnode/js/templates.0f988df6.js:1:558758)

猜测是事件侦听器内部有问题,所以我找了一段能捕获绑定事件侦听器的代码,代码如下:

var ListenerTracker = new function() {
    var is_active = false;
    /* listener tracking datas  */
    window._elements_ = [];
    window._listeners_ = [];
    this.init = function() {
        if (!is_active) {
            /*avoid duplicate call      */
            intercep_events_listeners();
        }
        is_active = true;
    };
    /* register individual element an returns its corresponding listeners  */
    var register_element = function(element) {
        if (_elements_.indexOf(element) == -1) { /* NB : split by useCapture to make listener easier to find when removing     */
            var elt_listeners = [{ /*useCapture=false*/ }, { /*useCapture=true*/ }];
            _elements_.push(element);
            _listeners_.push(elt_listeners);
        }
        return _listeners_[_elements_.indexOf(element)];
    };
    var intercep_events_listeners = function() {
        /* backup overrided methods    */
        var _super_ = {
            "addEventListener": HTMLElement.prototype.addEventListener,
            "removeEventListener": HTMLElement.prototype.removeEventListener
        };
        Element.prototype["addEventListener"] = function(type, listener, useCapture) {
            var listeners = register_element(this);
            /* add event before to avoid registering if an error is thrown     */
            _super_["addEventListener"].apply(this, arguments);
            /* adapt to 'elt_listeners' index    */
            useCapture = useCapture ? 1 : 0;
            if (!listeners[useCapture][type]) listeners[useCapture][type] = [];
            listeners[useCapture][type].push(listener);
        };
        Element.prototype["removeEventListener"] = function(type, listener, useCapture) {
            var listeners = register_element(this);
            /* add event before to avoid registering if an error is thrown     */
            _super_["removeEventListener"].apply(this, arguments);
            /* adapt to 'elt_listeners' index      */
            useCapture = useCapture ? 1 : 0;
            if (!listeners[useCapture][type]) return;
            var lid = listeners[useCapture][type].indexOf(listener);
            if (lid > -1) listeners[useCapture][type].splice(lid, 1);
        };
        Element.prototype["getEventListeners"] = function(type) {
            var listeners = register_element(this);
            /* convert to listener datas list    */
            var result = [];
            for (var useCapture = 0, list; list = listeners[useCapture]; useCapture++) {
                if (typeof(type) == "string") {
                    /* filtered by type       */
                    if (list[type]) {
                        for (var id in list[type]) {
                            result.push({
                                "type": type,
                                "listener": list[type][id],
                                "useCapture": !!useCapture
                            });
                        }
                    }
                } else {
                    /* all        */
                    for (var _type in list) {
                        for (var id in list[_type]) {
                            result.push({
                                "type": _type,
                                "listener": list[_type][id],
                                "useCapture": !!useCapture
                            });
                        }
                    }
                }
            }
            return result;
        };
    };
}();
ListenerTracker.init();

通过获取eruda._entryBtn._$el[0]绑定的全部事件得到以下内容(不知道为什么不是回调函数):

[{"pointerdown":[{"element":{},"$element":[{}],"options":{"containment":true},"position":{"x":0,"y":0},"startPoint":{"x":0,"y":0},"dragPoint":{"x":0,"y":0},"startPosition":{"x":0,"y":0},"_events":{"pointerDown":[null],"pointerMove":[null],"pointerUp":[null],"staticClick":[null],"dragStart":[null],"dragEnd":[null]},"isEnabled":true,"handles":[{}]}],"click":[{"element":{},"$element":[{}],"options":{"containment":true},"position":{"x":0,"y":0},"startPoint":{"x":0,"y":0},"dragPoint":{"x":0,"y":0},"startPosition":{"x":0,"y":0},"_events":{"pointerDown":[null],"pointerMove":[null],"pointerUp":[null],"staticClick":[null],"dragStart":[null],"dragEnd":[null]},"isEnabled":true,"handles":[{}]}]},{}]

对比能正常使用的网页所获取到的:

[{"pointerdown":[{"element":{},"options":{"containment":true},"position":{"x":0,"y":0},"startPoint":{"x":0,"y":0},"dragPoint":{"x":0,"y":0},"startPosition":{"x":0,"y":0},"_events":{"pointerDown":[null],"pointerMove":[null],"pointerUp":[null],"staticClick":[null],"dragStart":[null],"dragEnd":[null]},"isEnabled":true,"handles":[{}],"isPointerDown":false,"pointerDownPointer":{"pageX":413.8947448730469,"pageY":390.3157958984375}}],"click":[{"element":{},"options":{"containment":true},"position":{"x":0,"y":0},"startPoint":{"x":0,"y":0},"dragPoint":{"x":0,"y":0},"startPosition":{"x":0,"y":0},"_events":{"pointerDown":[null],"pointerMove":[null],"pointerUp":[null],"staticClick":[null],"dragStart":[null],"dragEnd":[null]},"isEnabled":true,"handles":[{}],"isPointerDown":false,"pointerDownPointer":{"pageX":413.8947448730469,"pageY":390.3157958984375}}]},{}]

最明显的就是缺失了pageX和pageY两个坐标,至于导致这个情况的原因,我是真的弄不明白无能为力了,希望能做出修复

问题2️⃣经过验证是因为我又把define恢复了,那么请问,假如不恢复define的话,会不会对网页内容造成影响,不会的话我就不恢复了

@lyk082401
Copy link

@1217965058 给你个临时解决方法

<script type="text/javascript" charset="utf-8">
// 替换原来的 define 函数
(function(window)
{
   if((typeof(window.define) == "function") && !window.hook_define)
   {
      window.hook_define = (function(/** _name, _module, _callback */)
      {
         var args = [], name, fn;
         window.Object.values(arguments).map(function(_value, _index, _values)
         {
            args.push(_value);
            if(typeof(_value) == "string")
            {
               name = _value;
            }
            if(typeof(_value) == "function")
            {
               fn = _value;
            }
         });
         (window.hook_define.hook_amd || (window.hook_define.hook_amd = {}))[(name && (name != "") && name) || new window.String(+new window.Date()).toString()] = fn();
         window.define.amd = window.hook_define.hook_amd;
         window.hook_define.define.apply(window.hook_define.define, arguments);
      });
      window.hook_define.define = window.define;
      window.Object.getOwnPropertyNames(window.define).map(function(_value, _index, _values)
      {
         window.hook_define[_value] = window.define[_value];
      });
      window.define = window.hook_define;
   }
})(window);
// 动态加载 Eruda
(function(window)
{
   var w = window;
   function loadJs(_url, _func, _cors)
   {
      var s = w.document.createElement("script"), p = w.document.head || (w.document.getElementsByTagName("head") && w.document.getElementsByTagName("head")[0]) || (w.document.body && w.document.body.parentNode && w.document.body.parentNode.appendChild(w.document.createElement("head"))) || w.document.body;
      s.src = _url;
      s.type = "text/javascript";
      s.charset = "utf-8";
      s.setAttribute("defer", "defer");
      s.setAttribute("async", "async");
      // https://developer.mozilla.org/zh-CN/docs/Web/HTML/CORS_settings_attributes
      if((_cors == null) || _cors)
      {
         s.setAttribute("crossorigin", "anonymous");
      }
      if(s.readyState)
      {
         s.onreadystatechange = (function()
         {
            try
            {
               if(this.readyState == "interactive"){}
               else if((this.readyState == "loaded") || (this.readyState == "complete"))
               {
                  _func && _func.apply(this, w.Array.prototype.concat.call(["load"], arguments));
               }
               else
               {
                  _func && _func.apply(this, w.Array.prototype.concat.call([this.readyState], arguments));
               }
            }
            catch(e)
            {
               w.console.error((w.alert((e && (e.stack || e.message)) || e), (e && (e.stack || e.message)) || e));
            }
         });
      }
      else
      {
         s.onload = s.onerror = s.onabort = (function()
         {
            try
            {
               _func && _func.apply(this, w.Array.prototype.concat.call([arguments[0].type], arguments));
            }
            catch(e)
            {
               w.console.error((w.alert((e && (e.stack || e.message)) || e), (e && (e.stack || e.message)) || e));
            }
         });
      }
      p.appendChild(s);
   }
   try
   {
      (w.eruda && (w.eruda._isInit || w.eruda.init(), true)) || loadJs("https://cdn.bootcdn.net/ajax/libs/eruda/2.3.3/eruda.min.js", function()
      {
          // 由于 Eruda 没有传入模块名,因此只能通过循环遍历来判断是不是 Eruda 对象
         w.define && w.define.amd && (function()
         {
            for(var key in w.define.amd)
            {
               if(w.define.amd.hasOwnProperty(key))
               {
                   // 找到 Eruda 对象
                  if(w.define.amd[key] && w.define.amd[key].init && w.define.amd[key].Console)
                  {
                      // 初始化 Eruda 对象,并添加到全局对象
                     w.eruda = (w.define.amd[key].init(), w.define.amd[key]);
                     break;
                  }
               }
            }
         })();
         // 若不存在 define,说明已被加载到全局对象,则直接初始化
         if(typeof(w.define) != "function")
         {
            var obj = w.eruda;
            (arguments[0] == "load") && obj && obj.init();
            w.alert([arguments[0], this.src, obj && obj.version]);
         }
      });
   }
   catch(e)
   {
      w.console.error((w.alert((e && (e.stack || e.message)) || e), (e && (e.stack || e.message)) || e));
   }
})(window);
</script>

以上只是一个暂时可行的方法,经测试可用。有什么疑问的话请加微信➕460437762。

@lyk082401
Copy link

lyk082401 commented Sep 20, 2020

@1217965058 另一个可行的方法

<script type="text/javascript" charset="utf-8">
	(function(window)
	{
		// For this kind of `EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src xxx.com".` is powerless.
		var isreq = false, urls = (
		{
			require: (
			{
				js: ["https://cdn.bootcdn.net/ajax/libs/require.js/2.3.6/require.min.js"]
			}),
			jquery: (
			{
				js: ["https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"]
			}),
			eruda: (
			{
				js: ["https://cdn.bootcdn.net/ajax/libs/eruda/2.4.0/eruda.min.js"]
			}),
			vconsole: (
			{
				js: ["https://cdn.bootcdn.net/ajax/libs/vConsole/3.3.4/vconsole.min.js"]
			}),
			toastr: (
			{
				js: ["https://cdn.bootcdn.net/ajax/libs/toastr.js/2.1.4/toastr.min.js"],
				css: ["https://cdn.bootcdn.net/ajax/libs/toastr.js/2.1.4/toastr.min.css"]
			})
		}), failure = (function(_xhr, _status, e)
		{
			(e || (e = _xhr)), window.console.error(e.stack || e.message || e), this && window.alert(this), (window.document.initTitle || (window.document.initTitle = window.document.title)), (window.document.title = ((this && [this, e].join(". ")) || e)), (window.document.historyTitle || (window.document.historyTitle = [])).push(window.document.title), window.setTimeout((function()
			{
				window.document.title = window.document.initTitle;
			}), 15000);
		}), ajaxEvaluate = (function(_url, _name, _success, _failure)
		{
			var xhr = (window.XMLHttpRequest && new window.XMLHttpRequest()) || (window.XDomainRequest && new window.XDomainRequest()) || (window.ActiveXObject && (function()
			{
				var versions = ["Microsoft.XMLHTTP", "MSXML.XMLHTTP", "MSXML2.XMLHTTP.7.0", "MSXML2.XMLHTTP.6.0", "MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP.2.0", "MSXML2.XMLHTTP"];
				for(var i = 0; i < versions.length; i++)
				{
					try
					{
						return new window.ActiveXObject(versions[i]);
					}
					catch(e)
					{
						window.console.error(e.stack || e.message || e);
					}
				}
				return {};
			})()) || {}, callback = (function(_event)
			{
				switch(_event.type)
				{
					case("abort"):case("error"):case("timeout"):
						_failure(_event);
						break;
					case("readystatechange"):case("loadstart"):
						break;
					case("progress"):
						if((xhr.readyState == 4) && (xhr.status == 200) && (xhr.response || xhr.responseText || xhr.responseXML))
						{
							(window.eval(xhr.response || xhr.responseText || xhr.responseXML) && (_success(window[_name]), true)) || _failure(xhr);
						}
						break;
					case("load"):case("loadend"):default:
						break;
				}
				window.console.log(_event.type, xhr.readyState, xhr.status, _event, xhr);
			}), origin = (function(_url)
			{
				return new window.RegExp("^(http|https)(\://)([a-zA-Z0-9_\.\-]+)((\:[0-9]{0,5})?)", "igm").exec(_url);
			});
			xhr.overrideMimeType && xhr.overrideMimeType("text/plain; charset=utf-8");
			window.Object.values(("abort error timeout readystatechange loadstart progress load loadend").split(" ")).map(function(_value, _index, _values)
			{
				xhr.addEventListener && xhr.addEventListener(_value, callback, false);
			});
			try
			{
				xhr.open && xhr.open("GET", _url, false);
				xhr.setRequestHeader && xhr.setRequestHeader("Accept", "*/*");
				xhr.setRequestHeader && xhr.setRequestHeader("User-Agent", window.navigator.userAgent);
				xhr.setRequestHeader && xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
				xhr.setRequestHeader && xhr._url && ((origin(xhr._url) && xhr.setRequestHeader("Origin", origin(xhr._url)[0])), xhr.setRequestHeader("Referer", xhr._url));
				xhr.send && xhr.send(null);
				if(xhr.response || xhr.responseText || xhr.responseXML)
				{
					(window.eval(xhr.response || xhr.responseText || xhr.responseXML) && (_success(window[_name]), true)) || _failure(xhr);
				}
			}
			catch(e)
			{
				throw e;
			}
		});
		// For RequireJS
		isreq && new window.Promise(function(_success, _failure)
		{
			window.console.log("RequireJS", _success, _failure);
			(window.require && (_success(window.require), true)) || ajaxEvaluate(urls.require.js[0], "require", _success, _failure);
		})
		.then((function(require)
		{
			var loadToastr = (function($)
			{
				// Toastr
				require([urls.toastr.js[0]], (function(_obj)
				{
					window.toastr || (window.toastr = _obj);
					window.console.log("Toastr", _obj);
					// Toastr CSS
					window.console.log("Toastr CSS", $("<link/>", (
					{
						href: urls.toastr.css[0],
						type: "text/css",
						charset: "utf-8",
						rel: "stylesheet",
						crossorigin: "anonymous",
						referrerpolicy: "unsafe-url"
					})).appendTo("head"));
				}), (function(e)
				{
					failure.bind("Toastr plugin load failure")(e);
					require.undef && require.undef(e.requireModules && e.requireModules[0]);
				}));
			});
			// jQuery
			(window.$ && (loadToastr(window.$), true)) || require([urls.jquery.js[0]], (function()
			{
				require(["jquery"], (function($)
				{
					window.$ || (window.$ = $);
					window.console.log("jQuery", $);
					loadToastr($);
				}), (function(e)
				{
					failure.bind("jQuery plugin load failure")(e);
					require.undef && require.undef(e.requireModules && e.requireModules[0]);
				}));
			}), (function(e)
			{
				failure.bind("jQuery plugin load failure")(e);
				require.undef && require.undef(e.requireModules && e.requireModules[0]);
			}));
			// Eruda
			window.eruda || require([urls.eruda.js[0]], (function(_obj)
			{
				window.eruda || (window.eruda = _obj).init();
				window.console.log("Eruda", _obj);
			}), (function(e)
			{
				failure.bind("Eruda plugin load failure")(e);
				require.undef && require.undef(e.requireModules && e.requireModules[0]);
			}));
			// vConsole
			window.vConsole || require([urls.vconsole.js[0]], (function()
			{
				require(["VConsole"], (function(_obj)
				{
					window.vConsole || (window.vConsole = new _obj());
					window.console.log("vConsole", _obj);
				}), (function(e)
				{
					failure.bind("vConsole plugin load failure")(e);
					require.undef && require.undef(e.requireModules && e.requireModules[0]);
				}));
			}), (function(e)
			{
				failure.bind("vConsole plugin load failure")(e);
				require.undef && require.undef(e.requireModules && e.requireModules[0]);
			}));
		}), (function(e)
		{
			failure.bind("RequireJS major plugin load failure")(e);
		}))
		.catch(function(e)
		{
			failure.bind("An error occurred with the plugin load")(e);
		});
		isreq || new window.Promise(function(_success, _failure)
		{
			window.console.log("jQuery", _success, _failure);
			(window.$ && (_success(window.$), true)) || ajaxEvaluate(urls.jquery.js[0], "$", _success, _failure);
		})
		.then((function($)
		{
			// 解决jQuery`3.0`之前的低版本会自动对数据进行JSON解析处理并在出错后直接抛出异常的问题
			$.ajaxSetup && $.ajaxSetup({dataType: "text"});
			// Eruda
			window.eruda || $.get(urls.eruda.js[0])
			.done(function(_data, _status, _xhr)
			{
				window.console.log("Eruda", _status, _xhr, _data && _data.slice(0, 100));
				window.eval(_data.replace("define([", 'define("eruda",[')) || window.alert("Eruda plugin load failure");
				if(("function" == typeof(window.define)) && window.define.amd)
				{
					window.require(["eruda"], (function(_obj)
					{
						(window.eruda = _obj).init();
					}), (function(e)
					{
						failure.bind("Eruda plugin load failure")(e);
						window.require.undef && window.require.undef(e.requireModules && e.requireModules[0]);
					}));
				}
				else
				{
					window.eruda.init();
				}
			})
			.fail(failure.bind("Eruda plugin load failure"));
			// vConsole
			window.vConsole || $.get(urls.vconsole.js[0])
			.done(function(_data, _status, _xhr)
			{
				window.console.log("vConsole", _status, _xhr, _data && _data.slice(0, 100));
				window.eval(_data) || window.alert("vConsole plugin load failure");
				if(("function" == typeof(window.define)) && window.define.amd)
				{
					window.require(["VConsole"], (function(_obj)
					{
						window.vConsole = new _obj();
					}), (function(e)
					{
						failure.bind("vConsole plugin load failure")(e);
						window.require.undef && window.require.undef(e.requireModules && e.requireModules[0]);
					}));
				}
				else
				{
					window.vConsole = new window.VConsole();
				}
			})
			.fail(failure.bind("vConsole plugin load failure"));
			// Toastr
			window.toastr || $.get(urls.toastr.js[0])
			.done(function(_data, _status, _xhr)
			{
				window.console.log("Toastr", _status, _xhr, _data && _data.slice(0, 100));
				if(("function" == typeof(window.define)) && window.define.amd)
				{
					window.eval(_data.replace("e([", 'e("toastr",[')) || window.alert("Toastr plugin load failure");
					window.require(["toastr"], (function(_obj)
					{
						window.toastr = _obj;
					}), (function(e)
					{
						failure.bind("Toastr plugin load failure")(e);
						window.require.undef && window.require.undef(e.requireModules && e.requireModules[0]);
					}));
				}
				else
				{
					window.eval(_data) || window.alert("Toastr plugin load failure");
				}
			})
			.fail(failure.bind("Toastr plugin load failure"))
			.always(function(_, _status, __)
			{
				// Toastr CSS
				$.get(urls.toastr.css[0])
				.done(function(_data, _status, _xhr)
				{
					window.console.log("Toastr CSS", _status, _xhr, _data && _data.slice(0, 100));
					$('<style type="text/css" charset="utf-8">' + _data + "</style>").appendTo("head").length || window.alert("Toastr style load failure");
				})
				.fail(failure.bind("Toastr style load failure"));
			});
		}), (function(e)
		{
			failure.bind("jQuery major plugin load failure")(e);
		}))
		.catch(function(e)
		{
			failure.bind("An error occurred with the plugin load")(e);
		});
	})(window);
</script>

@surunzi surunzi closed this as completed Nov 30, 2022
@MasterInQuestion
Copy link

    "假如不恢复define的话,会不会对网页内容造成影响"
+    Without restoring "define", shall it influence the original page intended?

    It depends, really depends.
    See also: https://github.com/liriliri/eruda/issues/143#issuecomment-2305990550

    At many times alike merely make no sense to the original developers:
    These are nothing, but random obscure libraries...

    Generally, seemingly OK = OK?
    Unused, then shouldn't break.

@MasterInQuestion
Copy link

MasterInQuestion commented Aug 23, 2024

    "个别网页 ... 使用过程中还是有各种各样的问题"
+    Certain pages ... Random problems during the usage

    I guess this is unfixable.
    Per nature of the JavaScript interface, things may inevitably conflict.

    Certain sites may even maliciously interrupt the Dev tools on some browsers...
    Ill-defined interfaces.

    Might be somehow related:
    https://github.com/liriliri/eruda/issues/445

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants