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

Enhanced loader for Eruda #327

Open
MasterInQuestion opened this issue May 1, 2023 · 1 comment
Open

Enhanced loader for Eruda #327

MasterInQuestion opened this issue May 1, 2023 · 1 comment

Comments

@MasterInQuestion
Copy link

MasterInQuestion commented May 1, 2023

    Enhanced loader for Eruda, in bookmarklet form.
    Attempt to workaround Eruda not loading due to site's CSP (Content Security Policy) configuration.

    When remote loading prevented by CSP, fallback attempts to retrieve Eruda's content from a local file.
    2 approaches initializing the script are tried:
    |1| Text in "<script>" element, inject and load. [1]
    |2| (if didn't work) Directly execute the script's text.
[1] Probably not much performance difference. Mostly for demo.

[[
javascript: (function () { window.define = undefined; var x0, x1, x = { defaults: { displaySize: 50 } }, x2 = ".eruda-container * { user-select: text !important; }", body = document.getElementsByTagName( "body" )[0]; body.appendChild( x0 = document.createElement( "script" ) ); x0.src = "https://cdn.jsdelivr.net/npm/eruda"; x0.onload = function () { eruda.init( x ); eruda.util.evalCss( x2 ); }; x0.onerror = function () { this.parentNode.removeChild( this ); body.appendChild( x0 = document.createElement( "input" ) ); x0.type = "file"; x0.onchange = function () { this.parentNode.removeChild( this ); x1 = new FileReader(); x1.onload = function () { x1 = x1.result + "\neruda.init(" + JSON.stringify( x ) + ");" + ' eruda.util.evalCss( "' + x2.replace( /(?=["\\])/g, '\\' ) + '" );'; try { body.appendChild( x0 = document.createElement( "script" ) ); x0.text = x1; } catch ( e ) {}; if ( "eruda" in window === false ) { x0.parentNode.removeChild( x0 ); Function( x1 )(); }; }; x1.readAsText( this.files[0] ); }; x0.style = "z-index: 2147483647; position: fixed; bottom: 0"; x0.click(); }; })();
]]

    Unrolled and commented:
[[

	(function () {
// >>>> (0)
	window.define = undefined;
	var x0, x1,
	x = { defaults: { displaySize: 50 } },
	x2 = ".eruda-container * { user-select: text !important; }",
// ^ https://github.com/liriliri/eruda/issues/461
	body = document.getElementsByTagName( "body" )[0];

	body.appendChild( x0 = document.createElement( "script" ) );
	x0.src = "https://cdn.jsdelivr.net/npm/eruda";
	x0.onload = function () { eruda.init( x ); eruda.util.evalCss( x2 ); };
	x0.onerror = function () {
// >>>> (1)
	this.parentNode.removeChild( this );
// Choose downloaded [ https://cdn.jsdelivr.net/npm/eruda ] for the file input.
	body.appendChild( x0 = document.createElement( "input" ) );
	x0.type = "file";
	x0.onchange = function () {
// >>>> (2)
	this.parentNode.removeChild( this );
	x1 = new FileReader();

	x1.onload = function () {
// >>>> (3)
	x1 = x1.result + "\neruda.init(" + JSON.stringify( x ) + ");" +
	' eruda.util.evalCss( "' + x2.replace( /(?=["\\])/g, '\\' ) + '" );';
	try {
	body.appendChild( x0 = document.createElement( "script" ) );
	x0.text = x1;
	} catch ( e ) {};

// "error" event does not trigger, so:
	if ( "eruda" in window === false ) {
// Guessed condition.
	x0.parentNode.removeChild( x0 );
	Function( x1 )(); // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval#never_use_direct_eval!
	};
// <<<< (3)
	};

	x1.readAsText( this.files[0] );
// <<<< (2)
	};

	x0.style = "z-index: 2147483647; position: fixed; bottom: 0";
	x0.click(); // May not work for certain browsers; attempted anyway.
// <<<< (1)
	};
// <<<< (0)
	})();

]]

    All `${Node}.parentNode.removeChild( ${Node} );` parts are not really necessary: merely included for saner DOM tree.
    See also:
    https://github.com/liriliri/eruda/discussions/326
    https://github.com/liriliri/eruda/issues/13

    Note Eruda expects "window.define" be undefined.
    See: https://github.com/liriliri/eruda/issues/143

    CSP failure may be critical so wrap "try { ... } catch ( e ) {};".
    [ https://caniuse.com/?search=try...catch ]

    Added extra handling of 2 minor improvements:
    |1| More reasonable default "displaySize".
    |2| Resolving potential misuse of "user-select: none".

@MasterInQuestion
Copy link
Author

MasterInQuestion commented Aug 23, 2024

    Derived cut-down version that directly attempts execute the script's text:
    javascript: (function () { window.define = undefined; var x0, x1, body = document.getElementsByTagName( "body" )[0]; body.appendChild( x0 = document.createElement( "script" ) ); x0.src = "https://cdn.jsdelivr.net/npm/eruda"; x0.onload = function () { eruda.init(); }; x0.onerror = function () { this.parentNode.removeChild( this ); body.appendChild( x0 = document.createElement( "input" ) ); x0.type = "file"; x0.onchange = function () { this.parentNode.removeChild( this ); x1 = new FileReader(); x1.onload = function () { Function( x1.result + "\neruda.init();" )(); }; x1.readAsText( this.files[0] ); }; x0.style = "z-index: 2147483647; position: fixed; bottom: 0"; x0.click(); }; })();

[[

	(function () {
// >>>> (0)
	window.define = undefined;
	var x0, x1,
	body = document.getElementsByTagName( "body" )[0];

	body.appendChild( x0 = document.createElement( "script" ) );
	x0.src = "https://cdn.jsdelivr.net/npm/eruda";
	x0.onload = function () { eruda.init(); };
	x0.onerror = function () {
// >>>> (1)
	this.parentNode.removeChild( this );
// Choose downloaded [ https://cdn.jsdelivr.net/npm/eruda ] for the file input.
	body.appendChild( x0 = document.createElement( "input" ) );
	x0.type = "file";
	x0.onchange = function () {
// >>>> (2)
	this.parentNode.removeChild( this );
	x1 = new FileReader();

	x1.onload = function () {
	Function( x1.result + "\neruda.init();" )();
	// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval#never_use_direct_eval!
	};

	x1.readAsText( this.files[0] );
// <<<< (2)
	};

	x0.style = "z-index: 2147483647; position: fixed; bottom: 0";
	x0.click(); // May not work for certain browsers; attempted anyway.
// <<<< (1)
	};
// <<<< (0)
	})();

]]

    Note this may fail for no "unsafe-eval".
    [ https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src#unsafe_eval_expressions ]

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

1 participant