Da musst du wohl echt nochmal auf díe Suche gehen. Meine (aktuellen) Chromes funktionieren auf Windows 10, Linux Manjaro, Android 9 und iPhone 11 (aktuelles iOS).Selbst mit Chrome aktuell, wird mir auf dem Mac die Ansicht der FB verweigert.
Eine kleine Anmerkung dazu: Es ist nicht Promise.resolve welches akut problematisch ist (das kann Firefox nämlich schon seit Version 29), sondern Promise.finally, welches in Firefox erst seit Version 58 unterstützt wird.Ich hab jetzt mal einen permanenten Scanner geschrieben der die Abhängigkeiten der JavaScript methoden des Browser-Checks im Detail aufzeigt.
// ==UserScript==
// @name Fritz!Box Polyfill
// @namespace http://www.buttercookie.de
// @include /https?:\/\/(.+\.)?(my)?fritz\.(box|nas)\//
// @version 1
// @run-at document-start
// @grant none
// ==/UserScript==
// Promise.prototype.finally polyfill (polyfill.io)
const promiseFinallyPolyfill = "(function(self, undefined) {function CreateMethodProperty(e,r,t){var a={value:t,writable:!0,enumerable:!1,configurable:!0};Object.defineProperty(e,r,a)}function Get(n,t){return n[t]}function IsCallablen{return'function'==typeof n}function ToObject(e){if(null===e||e===undefined)throw TypeError();return Object(e)}function GetV(t,e){return ToObject(t)[e]}function GetMethod(e,n){var r=GetV(e,n);if(null===r||r===undefined)return undefined;if(!1===IsCallabler)throw new TypeError('Method not callable: '+n);return r}function Type(e){switch(typeof e){case'undefined':return'undefined';case'boolean':return'boolean';case'number':return'number';case'string':return'string';case'symbol':return'symbol';default:return null===e?'null':'Symbol'in self&&(e instanceof self.Symbol||e.constructor===self.Symbol)?'symbol':'object'}}function IsConstructor(t){return'object'===Type(t)&&('function'==typeof t&&!!t.prototype)}function SpeciesConstructor(e,o){var r=Get(e,'constructor');if(r===undefined)return o;if('object'!==Typer)throw new TypeError('O.constructor is not an Object');var n='function'==typeof self.Symbol&&'symbol'==typeof self.Symbol.species?r[self.Symbol.species]:undefined;if(n===undefined||null===n)return o;if(IsConstructor(n))return n;throw new TypeError('No constructor found')}!function(){var t=Function.prototype.bind.call(Function.prototype.call,Promise.prototype.then),o=function(t,o){return new t(function(t){t(o())})};CreateMethodProperty(Promise.prototype,'finally',function(e){var r=this;if('object'!==Typer)throw new TypeError('Method %PromisePrototype%.finally called on incompatible receiver '+Object.prototype.toString.call(r));var n=SpeciesConstructor(r,Promise);if(!1===IsCallable(e))var i=e,c=e;else i=function(r){return t(o(n,e),function(){return r})},c=function(r){return t(o(n,e),function(){throw r})};return t(r,i,c)})}();})('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof global && global || {});";
const scriptElement = document.createElement('script');
scriptElement.textContent = promiseFinallyPolyfill;
const parentElement = document.head || document.documentElement;
parentElement.insertBefore(scriptElement, parentElement.firstChild);
Eine kleine Anmerkung dazu: Es ist nicht Promise.resolve welches akut problematisch ist (das kann Firefox nämlich schon seit Version 29), sondern Promise.finally, welches in Firefox erst seit Version 58 unterstützt wird.
Die fehlende Funktionalität lässt sich in diesem Fall nämlich glücklicherweise auch per Polyfill nachrüsten (hab mir eins von polyfill.io geschnappt), welches man dann z.B. per Userscript auf der Benutzeroberfläche der Fritzbox nachladen kann [...]
Nach Installation per Greasemonkey o.ä. wird der Browsercheck anstandslos passiert.
// ==UserScript==
// @name Fritz!Box Polyfill
// @namespace http://www.buttercookie.de
// @include /https?:\/\/(.+\.)?(my)?fritz\.(box|nas)\//
// @version 2
// @run-at document-start
// @grant GM_xmlhttpRequest
// ==/UserScript==
const polyfills = [/* Promise.prototype.finally polyfill (from polyfill.io)*/ "(function(self, undefined) {function CreateMethodProperty(e,r,t){var a={value:t,writable:!0,enumerable:!1,configurable:!0};Object.defineProperty(e,r,a)}function Get(n,t){return n[t]}function IsCallable(n){return'function'==typeof n}function ToObject(e){if(null===e||e===undefined)throw TypeError();return Object(e)}function GetV(t,e){return ToObject(t)[e]}function GetMethod(e,n){var r=GetV(e,n);if(null===r||r===undefined)return undefined;if(!1===IsCallable(r))throw new TypeError('Method not callable: '+n);return r}function Type(e){switch(typeof e){case'undefined':return'undefined';case'boolean':return'boolean';case'number':return'number';case'string':return'string';case'symbol':return'symbol';default:return null===e?'null':'Symbol'in self&&(e instanceof self.Symbol||e.constructor===self.Symbol)?'symbol':'object'}}function IsConstructor(t){return'object'===Type(t)&&('function'==typeof t&&!!t.prototype)}function SpeciesConstructor(e,o){var r=Get(e,'constructor');if(r===undefined)return o;if('object'!==Type(r))throw new TypeError('O.constructor is not an Object');var n='function'==typeof self.Symbol&&'symbol'==typeof self.Symbol.species?r[self.Symbol.species]:undefined;if(n===undefined||null===n)return o;if(IsConstructor(n))return n;throw new TypeError('No constructor found')}!function(){var t=Function.prototype.bind.call(Function.prototype.call,Promise.prototype.then),o=function(t,o){return new t(function(t){t(o())})};CreateMethodProperty(Promise.prototype,'finally',function(e){var r=this;if('object'!==Type(r))throw new TypeError('Method %PromisePrototype%.finally called on incompatible receiver '+Object.prototype.toString.call(r));var n=SpeciesConstructor(r,Promise);if(!1===IsCallable(e))var i=e,c=e;else i=function(r){return t(o(n,e),function(){return r})},c=function(r){return t(o(n,e),function(){throw r})};return t(r,i,c)})}();})('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof global && global || {});",
/* Spread syntax for object literals helper (from babeljs.io) */ "function ownKeys(object,enumerableOnly){var keys=Object.keys(object);if(Object.getOwnPropertySymbols){var symbols=Object.getOwnPropertySymbols(object);if(enumerableOnly) symbols=symbols.filter(function(sym){return Object.getOwnPropertyDescriptor(object,sym).enumerable});keys.push.apply(keys,symbols)} return keys} function _objectSpread(target){for(var i=1;i<arguments.length;i++){var source=arguments[i]!=null?arguments[i]:{};if(i%2){ownKeys(Object(source),!0).forEach(function(key){_defineProperty(target,key,source[key])})}else if(Object.getOwnPropertyDescriptors){Object.defineProperties(target,Object.getOwnPropertyDescriptors(source))}else{ownKeys(Object(source)).forEach(function(key){Object.defineProperty(target,key,Object.getOwnPropertyDescriptor(source,key))})}} return target} function _defineProperty(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0})}else{obj[key]=value} return obj}",
]
for (polyfill of polyfills) {
const scriptElement = document.createElement('script');
scriptElement.textContent = polyfill;
const parentElement = document.head || document.documentElement;
parentElement.insertBefore(scriptElement, parentElement.firstChild);
}
window.addEventListener('beforescriptexecute',
event => {
let originalScript = event.target;
if(/\/wizardhome\.js(\?.*)?$/.test(originalScript.src))
{
replaceScript(event, fixupWizardHome);
}
}
);
function fixupWizardHome(aInput) {
return aInput.replace('{...params}', '_objectSpread({}, params)');
}
function replaceScript(aBeforeScriptEvt, aFixupScriptCallback) {
aBeforeScriptEvt.preventDefault();
aBeforeScriptEvt.stopPropagation();
let originalScript = aBeforeScriptEvt.target;
GM_xmlhttpRequest({
method: "GET",
url: originalScript.src,
onload: res => {
let text = res.responseText;
text = aFixupScriptCallback(text);
let replacementScript = document.createElement('script');
replacementScript.textContent = text;
if (originalScript.hasAttribute('id')) {
replacementScript.id = originalScript.id;
}
originalScript.parentNode.replaceChild(replacementScript, originalScript);
}
});
}
Ja... ich habe unten im Fenster (Status-Leiste) mehrere Programme, wie Ghostery, NoScript usw., alle als schöne kleine Symbole, und auch einen Ladebalken usw. Bei allen späteren Firefox-Versionen scheint das nicht mehr so zu gehen, da sind dann nur noch mittelgroße Smbole + Text, was mir eben gar nicht gefällt... eben mit Firefox 55.0.1 getestet.Hat es einen bestimmten Grund, dass du genau auf Firefox 54 hängen geblieben bist?
Dieses Script funktioniert bei mir (in GreaseMonkey 3.17) nicht, genau so wenig wie Dein Script weiter oben zu 'Finally'... ich musste stattdessen den Code vonFalls das aus welchen Gründen auch immer keine Alternative ist (oder man z.B. stattdessen die 52 ESR nutzt), hier eine erweiterte Fassung meines Greasemonkey-Scriptes:
for (polyfill of polyfills)
-Block) in die Seite, genau so wie das Promise.prototype.finally
-Polyfill (welches bei dir warum auch immer nicht funktioniert).beforescriptexecute
-Eventhandler kann ich jedes Skript, welches die Fritzbox-Homepage zu laden versucht, abfangen. Sobald die wizardhome.js erkannt wird, tritt mein Code in Aktion: Mit preventDefault()
/stopPropagation()
blockiere ich die Ausführung des Originalskriptes. Per GM_xmlhttpRequest
hole ich mir dann den Inhalt des Skriptes, und biege per einfachem Suchen-und-Ersetzen (aInput.replace('{...params}', '_objectSpread({}, params)'
) die vom alten Firefox nicht unterstützte Spread-Syntax ({...params}
) auf meine oben geladene Hilfsfunktion (objectSpread()
) um.id
des originalen Skript-Tags zu übernehmen, damit der Fritzbox-Code das Skript beim Verlassen der Assistenten wieder entfernen kann.Komisch, ich hab jetzt eben nochmal getestet, und es läuft (auch wie von Dir beschrieben mit dem 'Hänger' beim ersten Aufruf der Assistenten). Könnte evtl. daran liegen, dass ich beim ersten Mal das Script von hier direkt über Zwischenablage in GreaseMonkey eingefügt hab; diesmal bin ich einen Zwischenschritt über Notepad++ gegangen, wo dann auch die richtige 'Formatierung' mit Einrückungen usw. gezeigt wurde statt eine einzige lange Zeile an Code...Hmm, warum das jetzt bei mir funktioniert (ebenfalls mit Greasemonkey 3.17) und bei dir nicht, weiß ich auch nicht.
GM_xmlhttpRequest()
standardmäßig asynchron funktioniert, d.h. während dem Abruf des originalen Skriptes wird die Ausführung meines Userskriptes unterbrochen, und in der Zwischenzeit kann dann irgendwelcher Fritzbox-Code laufen, der dann über das noch fehlende Assistenten-Skript stolpert. (Beim zweiten Mal funktioniert es dann vielleicht weil das Skript sofort aus dem Cache geladen wird und daher die Unterbrechung kürzer ausfällt? Weiß ich jetzt aber auch nicht sicher…).// ==UserScript==
// @name Fritz!Box Polyfill
// @namespace http://www.buttercookie.de
// @include /https?:\/\/(.+\.)?(my)?fritz\.(box|nas)\//
// @version 2.1
// @run-at document-start
// @grant GM_xmlhttpRequest
// ==/UserScript==
const polyfills = [/* Promise.prototype.finally polyfill (from polyfill.io) */ "(function(self, undefined) {function CreateMethodProperty(e,r,t){var a={value:t,writable:!0,enumerable:!1,configurable:!0};Object.defineProperty(e,r,a)}function Get(n,t){return n[t]}function IsCallable(n){return'function'==typeof n}function ToObject(e){if(null===e||e===undefined)throw TypeError();return Object(e)}function GetV(t,e){return ToObject(t)[e]}function GetMethod(e,n){var r=GetV(e,n);if(null===r||r===undefined)return undefined;if(!1===IsCallable(r))throw new TypeError('Method not callable: '+n);return r}function Type(e){switch(typeof e){case'undefined':return'undefined';case'boolean':return'boolean';case'number':return'number';case'string':return'string';case'symbol':return'symbol';default:return null===e?'null':'Symbol'in self&&(e instanceof self.Symbol||e.constructor===self.Symbol)?'symbol':'object'}}function IsConstructor(t){return'object'===Type(t)&&('function'==typeof t&&!!t.prototype)}function SpeciesConstructor(e,o){var r=Get(e,'constructor');if(r===undefined)return o;if('object'!==Type(r))throw new TypeError('O.constructor is not an Object');var n='function'==typeof self.Symbol&&'symbol'==typeof self.Symbol.species?r[self.Symbol.species]:undefined;if(n===undefined||null===n)return o;if(IsConstructor(n))return n;throw new TypeError('No constructor found')}!function(){var t=Function.prototype.bind.call(Function.prototype.call,Promise.prototype.then),o=function(t,o){return new t(function(t){t(o())})};CreateMethodProperty(Promise.prototype,'finally',function(e){var r=this;if('object'!==Type(r))throw new TypeError('Method %PromisePrototype%.finally called on incompatible receiver '+Object.prototype.toString.call(r));var n=SpeciesConstructor(r,Promise);if(!1===IsCallable(e))var i=e,c=e;else i=function(r){return t(o(n,e),function(){return r})},c=function(r){return t(o(n,e),function(){throw r})};return t(r,i,c)})}();})('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof global && global || {});",
/* Spread syntax for object literals helper (from babeljs.io) */ "function ownKeys(object,enumerableOnly){var keys=Object.keys(object);if(Object.getOwnPropertySymbols){var symbols=Object.getOwnPropertySymbols(object);if(enumerableOnly) symbols=symbols.filter(function(sym){return Object.getOwnPropertyDescriptor(object,sym).enumerable});keys.push.apply(keys,symbols)} return keys} function _objectSpread(target){for(var i=1;i<arguments.length;i++){var source=arguments[i]!=null?arguments[i]:{};if(i%2){ownKeys(Object(source),!0).forEach(function(key){_defineProperty(target,key,source[key])})}else if(Object.getOwnPropertyDescriptors){Object.defineProperties(target,Object.getOwnPropertyDescriptors(source))}else{ownKeys(Object(source)).forEach(function(key){Object.defineProperty(target,key,Object.getOwnPropertyDescriptor(source,key))})}} return target} function _defineProperty(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0})}else{obj[key]=value} return obj}",
]
for (polyfill of polyfills) {
const scriptElement = document.createElement('script');
scriptElement.textContent = polyfill;
const parentElement = document.head || document.documentElement;
parentElement.insertBefore(scriptElement, parentElement.firstChild);
}
window.addEventListener('beforescriptexecute',
event => {
let originalScript = event.target;
if(/\/wizardhome\.js(\?.*)?$/.test(originalScript.src))
{
replaceScript(event, fixupWizardHome);
}
}
);
function fixupWizardHome(aInput) {
return aInput.replace('{...params}', '_objectSpread({}, params)');
}
function replaceScript(aBeforeScriptEvt, aFixupScriptCallback) {
aBeforeScriptEvt.preventDefault();
aBeforeScriptEvt.stopPropagation();
let originalScript = aBeforeScriptEvt.target;
let response = GM_xmlhttpRequest({
method: "GET",
url: originalScript.src,
synchronous: true
});
text = aFixupScriptCallback(response.responseText);
let replacementScript = document.createElement('script');
replacementScript.textContent = text;
if (originalScript.hasAttribute('id')) {
replacementScript.id = originalScript.id;
}
originalScript.parentNode.replaceChild(replacementScript, originalScript);
}
Das läuft jetzt absolut 1A. Meinen herzlichsten Dank, Du bist echt super.Keine Ursache. Zum 'Hänger' hatte ich noch eine Vermutung, die sich tatsächlich bewahrheitet hat – es lag daran, dasGM_xmlhttpRequest()
standardmäßig asynchron funktioniert
var ok = true;
var nbc = gNbc || false;
try {
if (!nbc) {
ok = ok && window.Proxy && typeof new window.Proxy({
}, function () {
}) === 'object';
[
'1'
].forEach(function () {
});
ok = ok && window.Promise && typeof new window.Promise(function () {
}) === 'object';
ok = ok && window.Blob && typeof new window.Blob(['<a></a>'], {
type: 'text/html'
}) === 'object';
ok = ok && window.requestAnimationFrame && true;
ok = ok && window.Promise.resolve(true).finally(function () {
});
ok = ok && (typeof window.BigInt('1') === 'bigint');
}
} catch (err) {
ok = false;
}
if (!ok) {
window.location.href = 'sorry.lua';
}
browser.js
in der aktuellen Labor-Reihe aus.bigint
: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigIntbrowser.js
auf der Box wieder so ändert, daß dieser Test auf bigint
nicht erfolgt, der kann (vorerst) auch ohne eingeschränkte Funktionalität weiterhin mit einem Browser arbeiten, der den bigint
-Wrapper nicht unterstützt.PolyFill
o.ä. "nachbauen", sondern lediglich den zusätzlichen Test auf bigint
blockieren. Selbst wenn AVM das ggf. noch irgendwo nutzen wollte (vielleicht auch erst in der nächsten Version), dürften es nicht gleich alle Stellen in der Firmware sein, die dann nicht mehr funktionieren ... außerdem könnte/müßte AVM entsprechende Exceptions, wenn ein Objekt nicht erstellt werden kann, ordentlich abfangen können, so daß nicht gleich der komplette Prozess abbricht.nbc
auch eine Möglichkeit, diese Browser-Checks zu überspringen (das nbc
dürfte für no browser check
stehen).nbc
ergänzt (der Wert spielt keine Geige, nur dessen Existenz), dann sollte sich das FRITZ!OS-GUI auch mit einem älteren Browser aufrufen lassen. Wie man Parameter im "querystring" eines HTTP-Requests angibt, verrät eine Internet-Suche.bigint
-Objekten durch AVM nur die explizite Benutzung des Typs beinhaltete ... wenn da irgendwo noch "Konstanten" vorhanden sein sollten (also Zahlen, denen ein n
als Typ hinten angefügt wurde), dann wurden die bei meinem grep
nicht berücksichtigt.Ist da nicht das s zu viel?https://fritz.box/?nbc=1