sjehuda / Autonomous Browser

// ==UserScript== 
// @name        Autonomous Browser
// @description Automatic browser. To which adventure will it lead you?
// @author      Schimon Jehudah, Adv.
// @namespace   org.openuserjs.sjehuda.roboweb
// @homepageURL https://openuserjs.org/scripts/sjehuda/Autonomous_Browser
// @supportURL  https://openuserjs.org/scripts/sjehuda/Autonomous_Browser/issues
// @updateURL   https://openuserjs.org/meta/sjehuda/Autonomous_Browser.meta.js
// @copyright   2024, Schimon Jehudah (http://schimon.i2p)
// @license     MIT; https://opensource.org/licenses/MIT
// @version     24.11.27
// @run-at      document-start
// @match       *://*/*
// @icon        data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48dGV4dCB5PSIuOWVtIiBmb250LXNpemU9IjkwIj7wn5ay77iPPC90ZXh0Pjwvc3ZnPgo=
// ==/UserScript==

setInterval(function() {
  history.back()
}, 40000);

let contentReady = new Promise(function(resolve, reject) {
  //setTimeout(console.log('wait'), 10000)
  let request = new XMLHttpRequest();
  try {
  request.open('GET', location.href);
  request.onload = function() {
    if (request.status == 200) {
      resolve(request);
      console.log('contentReady.resolve()')
    } else {
      //alert('(request.status == 200) else')
      //history.back();
    }
  };
  //request.onprogress = function() {introPageLoader()};
  //request.onprogress = (event) => {introPageLoader()};
  request.onerror = function() {
    if (request.status == 403) {
      //alert('if (request.status == 403)')
      history.back();
    } else if (request.status == 404) {
      history.back();
      //alert('if (request.status == 404)')
    } else {
      //alert('else request.onerror')
      history.back();
    }
  };
  // try {request.send();} catch {history.back();}
  // Failed to load resource: the server responded with a status of 403 ()
  request.send();
  } catch {
    history.back();
  }
});

contentReady.then(
  function(request) {
    console.log('contentReady.then()')
    rawDocument = pageLoader(request);
    if (!isHTML()) {
      //alert('!isHTML()')
      history.back();
    }
    var drive = setInterval(
      approveLink,
      10000,
      rawDocument
    );
  },
  function(error) {
    history.back();
  }
);

const tldList = [
-2131357492,
-2095271699,
-1830313082,
-1752349395,
-1610658671,
-1542825754,
-1536293812,
-1473409395,
-1426426751,
-1328826067,
-1311829293,
 -779965899,
 -679381487,
 -657310838,
 -633654849,
 -373274299,
 -364826023,
 -138012666,
  -88694192,
  -78033866,
  107861201,
  110087831,
  413633535,
  533748962,
  667475342,
  736767581,
 1052592056,
 1078179023,
 1701667746,
 1942548305,
 1985010934,
 1078179023,
 -657310838,
 112291595, 
 -478448338,
 1242938149,

];

// Javascript implementation of Java’s String.hashCode() method
String.prototype.hashCode = function(){
  var hash = 0;
  if (this.length == 0) return hash;
  for (i = 0; i < this.length; i++) {
    char = this.charCodeAt(i);
    hash = ((hash<<5)-hash)+char;
    hash = hash & hash; // Convert to 32bit integer
  }
  return hash;
}
// Manwe Security Consulting

function pageLoader(request) {
  console.log('pageLoader()')
  const domParser = new DOMParser();
  const rawDocument = domParser.parseFromString(request.responseText, 'text/html');
  cssSelectors = [
    'audio', 'embed', 'form', 'iframe', 'input',
    'script', 'select', 'style', 'textarea', 'video'
  ];
  for (let i = 0; i < cssSelectors.length; i++) {
    console.log(cssSelectors[i])
    for (const item of rawDocument.querySelectorAll(cssSelectors[i])) {item.remove()}
  }
  const insertDocument = document.importNode(rawDocument.documentElement, true);
  const removeDocument = document.documentElement;
  try {
    document.replaceChild(insertDocument, removeDocument);
  } catch {
    history.back();
  }
  return rawDocument;
}

function approveLink(rawDocument) {
  console.log('approveLink()')
  link = pickURL(rawDocument);

  if (link) {
    link = link.href;
  } else {
    history.back();
  }

////  alert('link1: ' + link)
  switch (true) {
    case (link.endsWith('/')):
    case (link.endsWith('.php')):
    case (link.endsWith('.htm')):
    case (link.endsWith('.html')):
      break;
    case (isFileExtension(link)):
    case (isBlacklisted(link)):
    case (link.includes(':') && !link.startsWith('http')): // NOTE consider HTTPS
      //history.back();
      link = null;
      break;
  }
////    alert('* / ' + link.endsWith('/') + ' * php ' + link.endsWith('.php') + ' * htm ' + link.endsWith('.htm') + ' * html ' + link.endsWith('.html') + ' * isFileExtension(link) ' + isFileExtension(link) + ' * isBlacklisted(link) ' + isBlacklisted(link) + ' * link.includes(: and not start with http ' + (link.includes(':') && !link.startsWith('http')))
////  alert('link2: ' + link)

  if (link) {
    window.open(link, '_self');
  } else {
    history.back();
  }

}

function isHTML() {
  console.log('isHTML()')
  if (document.contentType == 'text/html') {
    return true;
  }
}

function pickURL(rawDocument) {
  console.log('pickURL()')
  links = rawDocument.querySelectorAll('a[href]');
  //if (links.length < 3) {return;}
  link = links[Math.floor(Math.random()*links.length)];
  return link;
}

function isFileExtension(link) {
  console.log('isFileExtension()')
  partedURL = link.split('/');
  console.log(partedURL)
  lastAfterSlash = partedURL[partedURL.length-1];
  console.log(lastAfterSlash)
  dot = lastAfterSlash.lastIndexOf('.');
  console.log(dot)
  if (dot < 0) {return;}
  fileExtension = lastAfterSlash.slice(dot);
  console.log(fileExtension)
  if (fileExtension.length < 8) {
    console.log('return true')
    return true;
  }
}

function isBlacklisted(link) {
  console.log('isBlacklisted()')
  console.log(link)
  host = new URL(link).host;
  hostParted = host.split('.');
  tld = hostParted[hostParted.length-2] + '.' + hostParted[hostParted.length-1];
  tldHash = tld.hashCode();
  if (tldList.includes(tldHash)) {
    return true;
  }
}