97 lines
2.7 KiB
JavaScript
97 lines
2.7 KiB
JavaScript
customElements.define(
|
|
'x-frame-bypass',
|
|
class extends HTMLIFrameElement {
|
|
static get observedAttributes() {
|
|
return ['src'];
|
|
}
|
|
constructor() {
|
|
super();
|
|
}
|
|
attributeChangedCallback() {
|
|
this.load(this.src);
|
|
}
|
|
connectedCallback() {
|
|
this.sandbox =
|
|
'' + this.sandbox ||
|
|
'allow-forms allow-modals allow-pointer-lock allow-same-origin allow-scripts allow-top-navigation-by-user-activation'; // all except allow-top-navigation
|
|
}
|
|
load(url, options) {
|
|
if (!url || !url.startsWith('http'))
|
|
throw new Error(`Unable to load src ${url} does not start with http(s)://`);
|
|
this.srcdoc = `<html>
|
|
<head>
|
|
<style>
|
|
.loader {
|
|
position: absolute;
|
|
top: calc(50% - 25px);
|
|
left: calc(50% - 25px);
|
|
width: 50px;
|
|
height: 50px;
|
|
background-color: #333;
|
|
border-radius: 50%;
|
|
animation: loader 1s infinite ease-in-out;
|
|
}
|
|
@keyframes loader {
|
|
0% {
|
|
transform: scale(0);
|
|
}
|
|
100% {
|
|
transform: scale(1);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="loader"></div>
|
|
</body>
|
|
</html>`;
|
|
this.fetchProxy(url, options, 0)
|
|
.then((res) => res.text())
|
|
.then((data) => {
|
|
if (data)
|
|
this.srcdoc = data.replace(
|
|
/<head([^>]*)>/i,
|
|
`<head$1>
|
|
<base href="${url}">
|
|
<script>
|
|
// X-Frame-Bypass navigation event handlers
|
|
document.addEventListener('click', e => {
|
|
if (frameElement && document.activeElement && document.activeElement.href) {
|
|
e.preventDefault()
|
|
frameElement.load(document.activeElement.href)
|
|
}
|
|
})
|
|
document.addEventListener('submit', e => {
|
|
if (frameElement && document.activeElement && document.activeElement.form && document.activeElement.form.action) {
|
|
e.preventDefault()
|
|
if (document.activeElement.form.method === 'post')
|
|
frameElement.load(document.activeElement.form.action, {method: 'post', body: new FormData(document.activeElement.form)})
|
|
else
|
|
frameElement.load(document.activeElement.form.action + '?' + new URLSearchParams(new FormData(document.activeElement.form)))
|
|
}
|
|
})
|
|
</script>`,
|
|
);
|
|
})
|
|
.catch((e) => console.error('Unable to load proxy iframe service', e));
|
|
}
|
|
fetchProxy(url, options, i) {
|
|
const proxies = (options || {}).proxies || [
|
|
'https://cors-anywhere.herokuapp.com/',
|
|
'https://api.codetabs.com/v1/proxy/?quest=',
|
|
];
|
|
return fetch(proxies[i] + url, options)
|
|
.then((res) => {
|
|
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
|
|
return res;
|
|
})
|
|
.catch((error) => {
|
|
if (i === proxies.length - 1) throw error;
|
|
return this.fetchProxy(url, options, i + 1);
|
|
});
|
|
}
|
|
},
|
|
{ extends: 'iframe' },
|
|
);
|