x-frame-bypass-1.0.2.js 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. customElements.define('x-frame-bypass', class extends HTMLIFrameElement {
  2. static get observedAttributes() {
  3. return ['src']
  4. }
  5. constructor () {
  6. super()
  7. }
  8. attributeChangedCallback () {
  9. this.load(this.src)
  10. }
  11. connectedCallback () {
  12. this.sandbox = '' + this.sandbox || 'allow-forms allow-modals allow-pointer-lock allow-popups allow-popups-to-escape-sandbox allow-presentation allow-same-origin allow-scripts allow-top-navigation-by-user-activation' // all except allow-top-navigation
  13. }
  14. load (url, options) {
  15. if (!url || !url.startsWith('http'))
  16. throw new Error(`X-Frame-Bypass src ${url} does not start with http(s)://`)
  17. console.log('X-Frame-Bypass loading:', url)
  18. this.srcdoc = `<html>
  19. <head>
  20. <style>
  21. .loader {
  22. position: absolute;
  23. top: calc(50% - 25px);
  24. left: calc(50% - 25px);
  25. width: 50px;
  26. height: 50px;
  27. background-color: #333;
  28. border-radius: 50%;
  29. animation: loader 1s infinite ease-in-out;
  30. }
  31. @keyframes loader {
  32. 0% {
  33. transform: scale(0);
  34. }
  35. 100% {
  36. transform: scale(1);
  37. opacity: 0;
  38. }
  39. }
  40. </style>
  41. </head>
  42. <body>
  43. <div class="loader"></div>
  44. </body>
  45. </html>`
  46. this.fetchProxy(url, options, 0).then(res => res.text()).then(data => {
  47. if (data)
  48. this.srcdoc = data.replace(/<head([^>]*)>/i, `<head$1>
  49. <base href="${url}">
  50. <script>
  51. // X-Frame-Bypass navigation event handlers
  52. document.addEventListener('click', e => {
  53. if (frameElement && document.activeElement && document.activeElement.href) {
  54. e.preventDefault()
  55. frameElement.load(document.activeElement.href)
  56. }
  57. })
  58. document.addEventListener('submit', e => {
  59. if (frameElement && document.activeElement && document.activeElement.form && document.activeElement.form.action) {
  60. e.preventDefault()
  61. if (document.activeElement.form.method === 'post')
  62. frameElement.load(document.activeElement.form.action, {method: 'post', body: new FormData(document.activeElement.form)})
  63. else
  64. frameElement.load(document.activeElement.form.action + '?' + new URLSearchParams(new FormData(document.activeElement.form)))
  65. }
  66. })
  67. </script>`)
  68. }).catch(e => console.error('Cannot load X-Frame-Bypass:', e))
  69. }
  70. fetchProxy (url, options, i) {
  71. const proxies = (options || {}).proxies || [
  72. window.BASE_URL + 'cors-anywhere?url=',
  73. 'https://cors-anywhere.herokuapp.com/',
  74. 'https://yacdn.org/proxy/',
  75. 'https://api.codetabs.com/v1/proxy/?quest='
  76. ]
  77. return fetch(proxies[i] + url, options).then(res => {
  78. if (!res.ok)
  79. throw new Error(`${res.status} ${res.statusText}`);
  80. return res
  81. }).catch(error => {
  82. if (i === proxies.length - 1)
  83. throw error
  84. return this.fetchProxy(url, options, i + 1)
  85. })
  86. }
  87. }, {extends: 'iframe'})