// chrome.js // Chrome Web Browser Debugging Interface for WelsonJS framework // Namhyeon Go // https://github.com/gnh1201/welsonjs var STD = require("lib/std"); var RAND = require("lib/rand"); var SHELL = require("lib/shell"); var SYS = require("lib/system"); var FILE = require("lib/file"); var HTTP = require("lib/http"); var Websocket = require("lib/websocket"); var AutoIt = require("lib/autoit"); var Toolkit = require("lib/toolkit"); var ExtraMath = require("lib/extramath"); // for remote debugging var pageEventId = 0; var ChromeObject = function() { STD.EventTarget.apply(this, arguments); // Set event-attachable object this.vendor = "Chrome"; this.workingDirectory = SYS.getEnvString("PROGRAMFILES") + "\\Google\\:installedDir\\Application"; this.binPath = SYS.getEnvString("PROGRAMFILES") + "\\Google\\:installedDir\\Application\\chrome.exe"; //this.processID = 0; this.installedDir = "Chrome"; this.profileName = "Default"; this.userDataDir = null; // proxy this.isPreventProxy = false; this.proxy = { "protocol": "socks5", "host": "127.0.0.1", "port": 1080, "ua": null }; this.inPrivate = false; // user agent this.userAgent = null; this.userAgents = []; // dependencies this.oAutoIt = null; // for remote debugging this.debuggingPort = 0; this.pageId = ""; this.ws = Websocket.create(); this.isAttached = false; this.pageList = []; this.title = ""; this.frameIndex = -1; this.isPreventEvaluate = false; this.isAppMode = false; this.baseScreenX = 0; this.baseScreenY = 0; this.create = function() { this.oAutoIt = AutoIt.create(); this.baseScreenX = 1; this.baseScreenY = (!this.isAppMode ? 84 : 32); return this; }; this.setIsPreventEvaluate = function(flag) { this.isPreventEvaluate = flag; }; this.setBinPath = function(path) { this.binPath = path; return this; }; this.setProfile = function(profileName, installedDir) { this.profileName = (profileName == "Default" ? "Chrome" : profileName); this.setInstalledDir(installedDir); this.workingDirectory = this.workingDirectory.replace(":installedDir", this.installedDir); this.binPath = this.binPath.replace(":installedDir", this.installedDir); //this.binPath = this.binPath.replace(":installedDir", "Chrome"); return this; }; this.clearProfile = function() { var FN = this.userDataDir; while (FILE.folderExists(FN)) { try { return FILE.deleteFolder(FN); } catch (e) { console.warn("Can not clear the session! Resaon: " + e.message); console.warn("Retrying clear the profile..."); } } }; this.clear = function() { return this.clearProfile(); }; this.setUserDataDir = function(dirname) { if (dirname != null) { this.userDataDir = dirname; } else { this.userDataDir = SHELL.getPathOfMyDocuments() + "\\UserData_Chrome_" + this.profileName; } return this; }; this.setInstalledDir = function(dirname) { if (dirname != null) { this.installedDir = dirname; } return this; }; this.setProxy = function(obj) { this.proxy = obj; return this; }; this.setProxyProtocol = function(s) { this.proxy.protocol = s; return this; }; this.setProxyHost = function(s) { this.proxy.host = s; return this; }; this.setProxyPort = function(port) { this.proxy.port = port; return this; }; this.setIsPreventProxy = function(flag) { this.isPreventProxy = flag; return this; }; this.setDebuggingPort = function(port) { this.debuggingPort = port; console.log("Enabled debugging port:", port); return this; }; this.setFrameIndex = function(idx) { this.frameIndex = idx; }; this.setPageId = function(s) { if (s == null) { var pageList = this.getPageList(); if (pageList instanceof Array && pageList.length > 0) { this.pageId = pageList[0].id; } } else { this.pageId = s; } }; this.createShoutcut = function(url) { if (!this.userDataDir) { this.userDataDir = SHELL.getPathOfMyDocuments() + "\\UserData_Chrome_" + this.profileName; } var cmd = [ "cscript", "app.js", "shoutcut.legacy", "chrome", this.installedDir, ]; // disable default browser check cmd.push("--no-default-browser-check"); // disable popop blocking cmd.push("--disable-popup-blocking"); // disable 3d cmd.push("--disable-3d-apis"); // block non-proxyed webrtc traffic cmd.push("--force-webrtc-ip-handling-policy=disable-non-proxied-udp"); // check incognito mode if (this.inPrivate) { cmd.push("--incognito"); } // check debugging port if (this.debuggingPort > 0) { cmd.push("--remote-debugging-port=" + this.debuggingPort); } cmd.push("--profile-directory=\"" + this.profileName + "\""); cmd.push("--user-data-dir=\"" + this.userDataDir + "\""); cmd.push("\"" + url + "\""); SHELL.createShoutcut("Chrome Prototype (" + this.installedDir + ")", cmd.join(' '), SYS.getCurrentScriptDirectory()); }; this.setInPrivate = function(flag) { this.inPrivate = flag; return this; }; this.setUserAgent = function(ua) { this.userAgent = ua; return this; }; this.addUserAgent = function(ua) { this.userAgents.push(ua); return this; }; this.addUserAgentsFromFile = function(filename) { var text = FILE.readFile(filename, FILE.CdoCharset.CdoUTF_8); var lines = text.split(/\r?\n/); for (var i = 0; i < lines.length; i++) { var line = lines[i].trim(); if (line !== "") { this.userAgents.push(line); } } return this; }; this.open = function(url) { this.setProfile(this.profileName, this.installedDir); // if the file does not exists, Check the 32bit installation folder again if (!FILE.fileExists(this.binPath)) { this.workingDirectory = SYS.getEnvString("PROGRAMFILES(X86)") + "\\Google\\:installedDir\\Application"; this.binPath = SYS.getEnvString("PROGRAMFILES(X86)") + "\\Google\\:installedDir\\Application\\chrome.exe"; this.setProfile(this.profileName, this.installedDir); } // find profile if (!FILE.fileExists(this.binPath)) { console.error("ChromeObject.open() -> '" + this.profileName + "' profile does not exists. You have to create it."); return this; } // create shoutcut to desktop if (this.debuggingPort == 0) { this.createShoutcut(); } /* var process; while (this.processID == 0) { try { if (!this.userDataDir) { this.userDataDir = SHELL.getPathOfMyDocuments() + "\\UserData_Chrome_" + this.profileName; } var shell = SHELL.create().setWorkingDirectory(this.workingDirectory); var process = shell.createProcess([ "\"" + this.binPath + "\"", "--profile-directory=\"" + this.profileName + "\"", "--proxy-server=\"socks5://127.0.0.1:" + this.proxyPort + "\"", "--user-data-dir=\"" + this.userDataDir + "\"", "\"" + url + "\"" ].join(" ")); sleep(1500); this.processID = process.ProcessID; sleep(1500); shell.release(); } catch (e) { console.error("ChromeObject.open() ->", e.message); sleep(1500); } } */ try { // get user data directory if (!this.userDataDir) { this.userDataDir = SHELL.getPathOfMyDocuments() + "\\UserData_Chrome_" + this.profileName; } // connect to shell var shell = SHELL.create(); shell.setWorkingDirectory(this.workingDirectory); // initialize var cmd = []; // enable inPrivate (incognito) mode if (this.inPrivate) { cmd.push("--incognito"); } // enable debugging port if (this.debuggingPort > 0) { cmd.push("--remote-debugging-port=" + this.debuggingPort); } // disable default browser check cmd.push("--no-default-browser-check"); // disable popop blocking cmd.push("--disable-popup-blocking"); // disable 3D cmd.push("--disable-3d-apis"); // block non-proxyed webrtc traffic cmd.push("--force-webrtc-ip-handling-policy=disable-non-proxied-udp"); // disable session crashed bubble ( //cmd.push("--disable-session-crashed-bubble"); // enable restore the last session //cmd.push("--restore-last-session"); // set profile directory cmd.push("--profile-directory=\"" + this.profileName + "\""); // set proxy configuration if (this.proxy != null && this.isPreventProxy != true) { console.log("Enabled proxy server:", this.proxy.protocol + "://" + this.proxy.host + ":" + this.proxy.port); cmd.push("--proxy-server=\"" + this.proxy.protocol + "://" + this.proxy.host + ":" + this.proxy.port + "\""); if (this.proxy.ua != null) { this.setUserAgent(this.proxy.ua); } } // set user data directory cmd.push("--user-data-dir=\"" + this.userDataDir + "\""); // choice user agent if (this.userAgent == null && this.userAgents.length > 0) { this.setUserAgent(RAND.one(this.userAgents)); } // set user agent if (this.userAgent != null) { cmd.push("--user-agent=\"" + this.userAgent + "\""); } // set the URL if (!this.isAppMode) { cmd.push("\"" + url + "\""); } else { cmd.push("--app=\"" + url + "\""); } // build the command line console.log(cmd.join(" ")); // run shell.runAs(this.binPath, cmd); sleep(300); // release shell shell.release(); } catch (e) { console.error("ChromeObject.open() -> ", e.message); sleep(300); } return this; }; this.getPageList = function() { var pageList = []; if (this.debuggingPort > 0) { try { //var responseText = HTTP.get("http://127.0.0.1:" + this.debuggingPort + "/json"); //console.log(responseText); //pageList = JSON.parse(responseText); var pageList = HTTP.create("CURL") .setDataType("json") .open("GET", "http://127.0.0.1:" + this.debuggingPort + "/json") .send() .responseBody ; this.pageList = pageList; return pageList; } catch (e) { console.error("ChromeObject.getPageList() ->", e.message); //return this.getPageList(); // 무한 루프 문제로 주석처리 return pageList; // 바로 넘김 } } else { console.error("Remote debugging unavailable"); return pageList; } }; this.getPageById = function(id) { return this.getPageList().find(function(x) { return (x.id == id); }); }; this.getPagesByUrl = function(url) { return this.getPageList().filter(function(x) { return (x.url.indexOf(url) == 0); }); }; this.getPagesByUrls = function(urls) { return this.getPageList().reduce(function(acc, x) { for (var i = 0; i < urls.length; i++) { if (x.url.indexOf(urls[i]) == 0) { acc.push(x); } } return acc; }, []); }; this.getPagesByTitle = function(title) { return this.getPageList().filter(function(x) { return (x.title.indexOf(title) == 0); }); }; this.getPagesByTitles = function(titles) { return this.getPageList().reduce(function(acc, x) { for (var i = 0; i < titles.length; i++) { if (x.title.indexOf(titles[i]) == 0) { acc.push(x); } } return acc; }, []); }; this.getParameterValue = function(paramName, defaultValue) { var paramValue = defaultValue; var page = this.getPageById(this.pageId); var params = page.url.split('&'); for (var i = 0; i < params.length; i++) { if (params[i].indexOf(paramName + '=') == 0) { paramValue = params[i].substring((paramName + '=').length); //break; // Do not break because will be get the last value } } return paramValue; }; this.sendPageRPC = function(method, params) { var result = null; try { if (this.pageId != "") { result = this.ws.send("ws://127.0.0.1:" + this.debuggingPort + "/devtools/page/" + this.pageId, JSON.stringify({ "id": pageEventId, "method": method, "params": params })); pageEventId++; console.log("ChromeObject().sendPageRPC() -> Sent"); } else { this.setPageId(null); if (this.pageId != "") { result = this.sendPageRPC(method, params); } else { console.error("Page not found"); } } } catch (e) { console.log("ChromeObject.sendPageRPC() ->", e.message); } return result; }; this.navigate = function(url) { return this.sendPageRPC("Page.navigate", { "url": url }); }; this.navigateEvaluately = function(url) { return this.evaluate('location.href = "' + url + '"'); }; this.evaluate = function(expression, frameIndex) { if (this.isPreventEvaluate) return; var frameIndex = (typeof frameIndex !== "undefined" ? frameIndex : this.frameIndex); if (frameIndex > -1) { expression = 'var __getFrame=function(e){return document.getElementsByTagName("frame")[e]},__getDocument=function(){return __getFrame(' + frameIndex + ').contentDocument||__getFrame(' + frameIndex + ').contentWindow.document},__getWindow=function(){return __getFrame(' + frameIndex + ').contentWindow};' + expression; } else { expression = 'var __getDocument=function(){return document},__getWindow=function(){return window};' + expression; } try { return this.sendPageRPC("Runtime.evaluate", { "expression": expression }); } catch (e) { console.error("ChromeObject.evaluate() ->", e.message); } }; this.getEvaluatedValue = function(expression) { try { var responseText = this.evaluate(expression); console.log(responseText); var result = JSON.parse(responseText).result.result.value; if (typeof(result) !== "undefined" && result != null) { return result; } else { return ""; } } catch (e) { console.error("ChromeObject.getEvaluatedValue() ->", e.message); return ""; } }; this.exit = function() { return this.sendPageRPC("Browser.close", {}); }; this.close = function() { var response = this.sendPageRPC("Page.close", {}); this.setPageId(null); return response; }; this.terminate = function() { try { this.oAutoIt.callFunction("WinKill", [this.getTitle()]); } catch (e) { console.error("ChromeObject.terminate() ->", e.message); } }; this.focus = function() { var title = ""; if (this.debuggingPort > 0) { try { // set page id if (this.pageId == "") { this.setPageId(null); } // calling _focus() title = this._focus(); // find window by title var pageList = this.getPageList(); if (pageList.length > 0) { this.oAutoIt.callFunction("WinActivate", [title]); } } catch (e) { console.error("ChromeObject.focus() ->", e.message); } } // calling `onfocus` event this.dispatchEvent(new STD.Event("focus")); return title; }; this._focus = function() { var title = ""; try { // get current title var _title = this.getTitle(); // if not focused if (_title.indexOf(this.pageId.substring(0, 6)) < 0) { // save previous title this.title = _title; // will be change title title = this.title + " " + this.pageId.substring(0, 6); // change webpage title for focusing window this.setTitle(title); } else { title = _title; /// when it is already catch } } catch (e) { console.error("ChromeObject._focus() ->", e.message); } return title; }; this.blur = function() { return this.setTitle(this.title); }; this.getScrollHeight = function(selector) { return parseInt(this.getEvaluatedValue('__getDocument().querySelector("' + selector + '").scrollHeight')); }; this.focusWithoutActivate = function() { if (this.debuggingPort > 0) { try { // if page ID is empty if (this.pageId == "") { var pageList = this.getPageList(); if (pageList instanceof Array && pageList.length > 0) { this.pageId = pageList[0].id; } } // change webpage title for focusing window this.setTitle(this.pageId); } catch (e) { console.error("ChromeObject.focusWithoutActivate() ->", e.message); } } }; this.autoAdjustByScreen = function(sX, sY, divX, divY) { // focus var title = this.focus(); sleep(300); // adjust window position and size var bX = Math.floor(sX / divX); var bY = Math.floor(sY / divY); var x = this.getRandomInt(0, bX); var y = this.getRandomInt(0, bY); var w = this.getRandomInt(bX * 3, sX - bX); var h = this.getRandomInt(bY, sY - bY); this.oAutoIt.callFunction("WinMove", [title, "", x, y, w, h]); // blur this.blur(); }; this.autoAdjustByWindow = function(sX, sY, w1, w2, h1, h2) { // catch focus var title = this.focus(); sleep(300); // adjust window position and size var w = this.getRandomInt(w1, w2); var h = this.getRandomInt(h1, h2); var x = this.getRandomInt(0, (sX - w < 0 ? parseInt(sX * 0.2) : (sX - w))); var y = this.getRandomInt(0, (sY - h < 0 ? parseInt(sY * 0.2) : (sY - h))); this.oAutoIt.callFunction("WinMove", [title, "", x, y, w, h]); // blur this.blur(); }; this.downMouseWheel = function(times) { if (this.debuggingPort > 0) { try { var pos = this.getScreenPosition(); this.oAutoIt.callFunction("MouseMove" [pos.x + 100, pos.y + 100]); this.oAutoIt.callFunction("MouseWheel", ["down", times]); } catch (e) { console.error("ChromeObject.downMouseWheel() ->", e.message); } } }; this.upMouseWheel = function(times) { if (this.debuggingPort > 0) { try { var pos = this.getScreenPosition(); this.oAutoIt.callFunction("MouseMove", [pos.x + 100, pos.y + 100]); this.oAutoIt.callFunction("MouseWheel", ["up", times]); } catch (e) { console.error("ChromeObject.upMouseWheel() ->", e.message); } } }; this.setTitle = function(title) { var i = 0, repeat = 2; if (this.debuggingPort > 0) { while (i < repeat) { this.evaluate('document.title = ' + this.__escape(title)); i++; } } }; this.getTitle = function() { if (this.debuggingPort > 0) { return this.getEvaluatedValue('document.title'); } }; this.getScreenPosition = function() { var result = this.getEvaluatedValue('(function() { return [__getWindow().screenX, __getWindow().screenY].join(","); })();'); var pos = result.split(','); return { "x": parseInt(pos[0]), "y": parseInt(pos[1]) }; }; this.getElementPosition = function(selector, startIndex) { var startIndex = (typeof startIndex !== 'undefined' ? startIndex : 0); var result; var pos = -1; if (startIndex > 0) { result = this.getEvaluatedValue('(function(k) { var rect = __getDocument().querySelectorAll("' + selector + '")[k].getBoundingClientRect(); return [parseInt(rect.left), parseInt(rect.top), parseInt(__getWindow().pageXOffset + rect.left), parseInt(__getWindow().pageYOffset + rect.top), parseInt(rect.width), parseInt(rect.height)].join(","); })(' + startIndex + ');'); } else { result = this.getEvaluatedValue('(function() { var rect = __getDocument().querySelector("' + selector + '").getBoundingClientRect(); return [parseInt(rect.left), parseInt(rect.top), parseInt(__getWindow().pageXOffset + rect.left), parseInt(__getWindow().pageYOffset + rect.top), parseInt(rect.width), parseInt(rect.height)].join(","); })();'); } pos = result.split(','); if (pos.length == 6) { return { "x": parseInt(pos[0]), "y": parseInt(pos[1]), "a": parseInt(pos[2]), "b": parseInt(pos[3]), "w": parseInt(pos[4]), "h": parseInt(pos[5]) }; } else { return { "x": -1, "y": -1, "a": -1, "b": -1, "g": -1, "d": -1 }; } }; this.getElementPositionByText = function(selector, searchText) { var result; var pos = -1; var s = '(function() {' + ' var element = Object.values(__getDocument().querySelectorAll("' + selector + '")).find(function(x) {' + ' return (x.innerText.indexOf(' + this.__escape() + ') > -1);' + ' });' + ' if (element) {' + ' var rect = element.getBoundingClientRect();' + ' return [parseInt(rect.left), parseInt(rect.top), parseInt(__getWindow().pageXOffset + rect.left), parseInt(__getWindow().pageYOffset + rect.top), parseInt(rect.width), parseInt(rect.height)].join(",");' + ' }' + '})()' ; result = this.getEvaluatedValue(s); pos = result.split(','); if (pos.length == 6) { return { "x": parseInt(pos[0]), "y": parseInt(pos[1]), "a": parseInt(pos[2]), "b": parseInt(pos[3]), "w": parseInt(pos[4]), "h": parseInt(pos[5]) }; } else { return { "x": -1, "y": -1, "a": -1, "b": -1, "g": -1, "d": -1 }; } }; this.getNestedElementPosition = function(selector, subSelector, searchText, startIndex) { var s = ''; var startIndex = (typeof startIndex !== 'undefined' ? startIndex : 0); if (searchText.indexOf(':tokenize(') == 0) { searchText = searchText.substring(searchText.indexOf('(') + 1, searchText.lastIndexOf(')')); s += '(function() {' + ' var elements = Object.values(__getDocument().querySelectorAll("' + selector + '")).filter(function(x) {' + ' var el = ' + (subSelector == ':self' ? 'x;' : 'x.querySelector("' + subSelector + '");') + ' var keywords = ' + this.__escape(searchText) + '.trim().split(" ");' + ' var text = el instanceof HTMLElement ? [el.innerText, el.getAttribute("aria-label"), el.getAttribute("class")].join(" ") : "";' + ' return (text.split(" ").filter(function(w) { return keywords.indexOf(w) > -1; }).length >= keywords.length);' + ' ' + (startIndex > 0 ? '}).slice(' + startIndex + ');' : '});') + ' if (elements.length > 0) {' + ' var element = elements[0];' + ' var rect = element.getBoundingClientRect();' + ' var elClassName = "welsonjs_" + parseInt(Math.random() * 1000000000);' + ' element.setAttribute("class", element.getAttribute("class") + " " + elClassName);' + ' return [parseInt(rect.left), parseInt(rect.top), parseInt(__getWindow().pageXOffset + rect.left), parseInt(__getWindow().pageYOffset + rect.top), parseInt(rect.width), parseInt(rect.height), "." + elClassName].join(",");' + ' } else {' + ' return "";' + ' }' + '})()' ; } else if (searchText.indexOf(':text(') == 0) { this.evaluate(ExtraMath.export_measureSimilarity()); searchText = searchText.substring(searchText.indexOf('(') + 1, searchText.lastIndexOf(')')); s += '(function() {' + ' var elements = Object.values(__getDocument().querySelectorAll("' + selector + '")).filter(function(x) {' + ' var el = ' + (subSelector == ':self' ? 'x;' : 'x.querySelector("' + subSelector + '");') + ' var searchText = ' + this.__escape(searchText) + '.trim();' + ' var text = el instanceof HTMLElement ? el.innerText : "";' + ' return ExtraMath.measureSimilarity(text, searchText) >= 0.9;' + ' ' + (startIndex > 0 ? '}).slice(' + startIndex + ');' : '});') + ' if (elements.length > 0) {' + ' var element = elements[0];' + ' var rect = element.getBoundingClientRect();' + ' var elClassName = "welsonjs_" + parseInt(Math.random() * 1000000000);' + ' element.setAttribute("class", element.getAttribute("class") + " " + elClassName);' + ' return [parseInt(rect.left), parseInt(rect.top), parseInt(__getWindow().pageXOffset + rect.left), parseInt(__getWindow().pageYOffset + rect.top), parseInt(rect.width), parseInt(rect.height), "." + elClassName].join(",");' + ' } else {' + ' return "";' + ' }' + '})()' ; } else if (searchText.indexOf(':p(') == 0) { var p = parseFloat(searchText.substring(searchText.indexOf('(') + 1, searchText.lastIndexOf(')'))); if (p > 0) { s += '(function() {' + ' var elements = Object.values(__getDocument().querySelectorAll("' + selector + '")).filter(function(x) {' + ' return (Math.random() < ' + p + ');' + ' ' + (startIndex > 0 ? '}).slice(' + startIndex + ');' : '});') + ' if (elements.length > 0) {' + ' var element = elements[0];' + ' var rect = element.getBoundingClientRect();' + ' var elClassName = "welsonjs_" + parseInt(Math.random() * 1000000000);' + ' element.setAttribute("class", element.getAttribute("class") + " " + elClassName);' + ' return [parseInt(rect.left), parseInt(rect.top), parseInt(__getWindow().pageXOffset + rect.left), parseInt(__getWindow().pageYOffset + rect.top), parseInt(rect.width), parseInt(rect.height), "." + elClassName].join(",");' + ' } else {' + ' return "";' + ' }' + '})()' ; } else { s += '(function() {' + ' var elements = Object.values(__getDocument().querySelectorAll("' + selector + '"));' + ' ' + (startIndex > 0 ? 'elements = elements.slice(' + startIndex + ');' : '') + ' if (elements.length > 0) {' + ' var k = Math.floor(Math.random() * elements.length);' + ' var element = elements[k];' + ' var rect = element.getBoundingClientRect();' + ' var elClassName = "welsonjs_" + parseInt(Math.random() * 1000000000);' + ' element.setAttribute("class", element.getAttribute("class") + " " + elClassName);' + ' return [parseInt(rect.left), parseInt(rect.top), parseInt(__getWindow().pageXOffset + rect.left), parseInt(__getWindow().pageYOffset + rect.top), parseInt(rect.width), parseInt(rect.height), "." + elClassName].join(",");' + ' } else {' + ' return "";' + ' }' + '})()' ; } } else { s += '(function() {' + ' var elements = Object.values(__getDocument().querySelectorAll("' + selector + '")).filter(function(x) {' + ' var el = ' + (subSelector == ':self' ? 'x;' : 'x.querySelector("' + subSelector + '");') + ' var searchText = ' + this.__escape(searchText) + '.trim();' + ' var text = el instanceof HTMLElement ? [el.innerText, el.getAttribute("aria-label"), el.getAttribute("class")].join(" ") : "";' + ' return (text.indexOf(searchText) > -1);' + ' ' + (startIndex > 0 ? '}).slice(' + startIndex + ');' : '});') + ' if (elements.length > 0) {' + ' var element = elements[0];' + ' var rect = element.getBoundingClientRect();' + ' var elClassName = "welsonjs_" + parseInt(Math.random() * 1000000000);' + ' element.setAttribute("class", element.getAttribute("class") + " " + elClassName);' + ' return [parseInt(rect.left), parseInt(rect.top), parseInt(__getWindow().pageXOffset + rect.left), parseInt(__getWindow().pageYOffset + rect.top), parseInt(rect.width), parseInt(rect.height), "." + elClassName].join(",");' + ' } else {' + ' return "";' + ' }' + '})()' ; } var result = this.getEvaluatedValue(s); var pos = result.split(','); if (pos.length == 7) { return { "x": parseInt(pos[0]), "y": parseInt(pos[1]), "a": parseInt(pos[2]), "b": parseInt(pos[3]), "w": parseInt(pos[4]), "h": parseInt(pos[5]), "s": pos[6] }; } else { return { "x": -1, "y": -1, "a": -1, "b": -1, "w": -1, "h": -1, "s": "" }; } }; this.triggerEventOnNestedElement = function(eventName, selector, subSelector, searchText, startIndex) { var s = ''; var startIndex = (typeof startIndex !== 'undefined' ? startIndex : 0); if (searchText.indexOf(':tokenize(') == 0) { searchText = searchText.substring(searchText.indexOf('(') + 1, searchText.lastIndexOf(')')); s += '(function() {' + ' var elements = Object.values(__getDocument().querySelectorAll("' + selector + '")).filter(function(x) {' + ' var el = ' + (subSelector == ':self' ? 'x;' : 'x.querySelector("' + subSelector + '");') + ' var keywords = ' + this.__escape(searchText) + '.trim().split(" ");' + ' var text = el instanceof HTMLElement ? [el.innerText, el.getAttribute("aria-label"), el.getAttribute("class")].join(" ") : "";' + ' return (text.split(" ").filter(function(w) { return keywords.indexOf(w) > -1; }).length >= keywords.length);' + ' ' + (startIndex > 0 ? '}).slice(' + startIndex + ');' : '});') + ' if (elements.length > 0) {' + ' elements[0].' + (eventName == 'click' ? 'click()' : 'dispatchEvent(new Event("' + eventName + '"))') + ';' + ' }' + '})()' ; } else if (searchText.indexOf(':p(') == 0) { var p = parseFloat(searchText.substring(searchText.indexOf('(') + 1, searchText.lastIndexOf(')'))); if (p > 0) { s += '(function() {' + ' var elements = Object.values(__getDocument().querySelectorAll("' + selector + '")).filter(function(x) {' + ' return (Math.random() < ' + p + ');' + ' ' + (startIndex > 0 ? '}).slice(' + startIndex + ');' : '});') + ' if (elements.length > 0) {' + ' elements[0].' + (eventName == 'click' ? 'click()' : 'dispatchEvent(new Event("' + eventName + '"))') + ';' + ' }' + '})()' ; } else { s += '(function() {' + ' var elements = Object.values(__getDocument().querySelectorAll("' + selector + '"));' + ' ' + (startIndex > 0 ? 'elements = elements.slice(' + startIndex + ');' : '') + ' if (elements.length > 0) {' + ' var k = Math.floor(Math.random() * elements.length);' + ' elements[k].' + (eventName == 'click' ? 'click()' : 'dispatchEvent(new Event("' + eventName + '"))') + ';' + ' }' + '})()' ; } } else { s += '(function() {' + ' var elements = Object.values(__getDocument().querySelectorAll("' + selector + '")).filter(function(x) {' + ' var el = ' + (subSelector == ':self' ? 'x;' : 'x.querySelector("' + subSelector + '");') + ' var searchText = ' + this.__escape(searchText) + '.trim();' + ' var text = el instanceof HTMLElement ? [el.innerText, el.getAttribute("aria-label"), el.getAttribute("class")].join(" ") : "";' + ' return (text.indexOf(searchText) > -1);' + ' ' + (startIndex > 0 ? '}).slice(' + startIndex + ');' : '});') + ' if (elements.length > 0) {' + ' elements[0].' + (eventName == 'click' ? 'click()' : 'dispatchEvent(new Event("' + eventName + '"))') + ';' + ' }' + '})()' ; } return this.evaluate(s); }; this.getNestedElementIndex = function(selector, subSelector, searchText) { var s = ''; s += '(function() {' + ' var elements = Object.values(__getDocument().querySelectorAll("' + selector + '"));' + ' var result = -1;' + ' for (var i = 0; i < elements.length; i++) {' + ' if (x.querySelector("' + subSelector + '").innerText.indexOf(' + this.__escape(searchText) + ') > -1) {' + ' result = i;' + ' break;' + ' }' + ' }' + ' return result;' + '})()' ; return parseInt(this.getEvaluatedValue(s)); }; this.getElementCount = function(selector) { return this.getEvaluatedValue('document.querySelectorAll("' + selector + '").length'); }; this.getPageHeight = function() { var height = 0; if (this.debuggingPort > 0) { var result = this.getEvaluatedValue('(function(obj) { return Math.max(obj.scrollHeight, obj.clientHeight); })(__getDocument().querySelector("html"))'); height = parseInt(result); } return height; }; this.setIsAttached = function(isAttached) { this.isAttached = isAttached; return this; }; this.getRandomInt = function(min, max) { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min + 1)) + min; }; this.checkDebuggingPort = function() { var isChecked = false; var isDone = false; while (!isDone) { try { if (this.debuggingPort > 0) { var result = SHELL.exec("netstat -ano | findstr :" + this.debuggingPort); if (result.indexOf(":" + this.debuggingPort) > -1) { isChecked = true; } } isDone = true; } catch(e) { sleep(1); console.error("ChromeObject.checkDebuggingPort() ->", e.message); } } return isChecked; }; this.getCurrentUrl = function() { var page = this.getPageById(this.pageId); return page.url; }; this.getCurrentDomain = function() { return this.getEvaluatedValue('__getDocument().domain') || ''; }; this.triggerEvent = function(eventName, selector) { if (selector.indexOf(':p(') < 0) { if (eventName == 'click') { return this.evaluate('__getDocument().querySelector("' + selector + '").click()'); } else { return this.evaluate('__getDocument().querySelector("' + selector + '").dispatchEvent(new Event("' + eventName + '"))'); } } else { var p = parseFloat(selector.substring(selector.indexOf('(') + 1, selector.indexOf(')'))); var _selector = selector.substring(0, selector.indexOf(':')); if (p > 0) { return this.evaluate('(function(obj, p) { var element = Object.values(obj).find(function() { return (Math.random() < p); }); if(element) element.click(); })(__getDocument().querySelectorAll("' + _selector + '"), ' + p + ')'); } else { return this.evaluate('(function(obj) { var elements = Object.values(obj); var element = elements[Math.floor(Math.random() * elements.length)]; if(element) element.click(); })(__getDocument().querySelectorAll("' + _selector + '"))'); } } }; this.triggerEventByFind = function(eventName, selector, searchText) { var s = '(function() {' + ' var element = Object.values(__getDocument().querySelectorAll("' + selector + '")).find(function(x) {' + ' return (x.innerText.indexOf(' + this.__escape(searchText) + ') > -1);' + ' });' + ' if (element) {' + ' element.' + (eventName == 'click' ? 'click()' : 'dispatchEvent(new Event("' + eventName + '"))') + ';' + ' }' + '})()' ; return this.evaluate(s); }; this.triggerEventOnNestedFind = function(eventName, selector, subSelector, searchText) { var s = '(function() {' + ' var element = Object.values(__getDocument().querySelectorAll("' + selector + '")).find(function(x) {' + ' return (x.querySelector("' + subSelector + '").innerText.indexOf(' + this.__escape(searchText) + ') > -1);' + ' });' + ' if (element) {' + ' element.' + (eventName == 'click' ? 'click()' : 'dispatchEvent(new Event("' + eventName + '"))') + ';' + ' }' + '})()' ; return this.evaluate(s); }; this.scrollTo = function(x, y) { return this.evaluate('__getWindow().scrollTo(parseInt(' + x + '), parseInt(' + y + '))'); }; this.scrollBy = function(dx, dy) { return this.evaluate('__getWindow().scrollBy(parseInt(' + dx + '), parseInt(' + dy + '))'); }; this.scrollToElement = function(selector, dx, dy) { return this.evaluate('(function(rect, dx, dy) { __getWindow().scrollTo(rect.x + dx, rect.y + dy); })(__getDocument().querySelector("' + selector + '").getBoundingClientRect(), parseInt("' + dx + '"), parseInt("' + dy + '"))'); }; this.reload = function() { //return this.sendPageRPC("Page.reload", {}); return this.evaluate("__getWindow().reload()"); }; this.hasClass = function(seletctor, className) { try { var result = this.getEvaluatedValue('__getDocument().querySelector("' + seletctor + '").getAttribute("class")'); if (typeof(result) === "string") { return (result.split(' ').indexOf(className) > -1); } else { return false; } } catch (e) { console.error("ChromeObject.hasClass() ->", e.message); } }; this.getAttribute = function(selector, attributeName) { return this.getEvaluatedValue('__getDocument().querySelector("' + selector + '").getAttribute("' + attributeName + '")'); }; this.sendKeys = function(s) { this.oAutoIt.callFunction("Send", [s]); }; this.sendSpaceKey = function() { this.oAutoIt.callFunction("Send", ["{SPACE}"]); }; this.setValue = function(selector, value, repeat, searchIndex) { var s = value, i = 0, searchIndex = (typeof searchIndex !== "undefined" ? searchIndex : 0), repeat = (typeof repeat !== "undefined" ? repeat : 1) ; while (i < repeat) { if (searchIndex > 0) { this.evaluate('Object.values(__getDocument().querySelectorAll("' + selector + '"))[' + searchIndex + '].value = ' + this.__escape(s)); } else { this.evaluate('__getDocument().querySelector("' + selector + '").value = ' + this.__escape(s)); } i++; } }; this.getText = function(selector) { return this.getEvaluatedValue('__getDocument().querySelector("' + selector + '").innerText'); }; this.setHTML = function(selector, value, repeat, searchIndex) { var s = value, i = 0, searchIndex = (typeof searchIndex !== "undefined" ? searchIndex : 0), repeat = (typeof repeat !== "undefined" ? repeat : 1) ; while (i < repeat) { if (searchIndex > 0) { this.evaluate('Object.values(__getDocument().querySelectorAll("' + selector + '"))[' + searchIndex + '].value = ' + this.__escape(s)); } else { this.evaluate('__getDocument().querySelector("' + selector + '").innerHTML = ' + this.__escape(s)); } i++; } }; this.getHTML = function(selector) { return this.getEvaluatedValue('__getDocument().querySelector("' + selector + '").innerHTML'); }; this.traceMouseClick = function() { return this.evaluate('__getWindow().addEventListener("click",function(e){var t=e.clientX,n=e.clientY,l=__getDocument().createElement("div");l.style.position="absolute",l.style.width="20px",l.style.height="20px",l.style.backgroundColor="#00ff00",l.style.zIndex=99999,l.style.top=__getWindow().pageYOffset+n-10+"px",l.style.left=__getWindow().pageXOffset+t-10+"px",__getDocument().body.appendChild(l)});'); }; // Added in 2023-12-27 this.markPosition = function(x, y) { return this.evaluate('(function(x, y){var t=x,n=y,l=__getDocument().createElement("div");l.style.position="absolute",l.style.width="20px",l.style.height="20px",l.style.backgroundColor="#ff0000",l.style.zIndex=99999,l.style.top=__getWindow().pageYOffset+n-10+"px",l.style.left=__getWindow().pageXOffset+t-10+"px",__getDocument().body.appendChild(l)})(' + parseInt(x) + ', ' + parseInt(y) + ');'); }; // Added in 2023-12-27 this.getTextsBySelectorAll = function(selector) { return JSON.parse(this.getEvaluatedValue('JSON.stringify(Object.values(__getDocument().querySelectorAll("' + selector + '")).reduce(function(a, x) { a.push(x.innerText); return a; }, []))')); }; this.getWindowInnerHeight = function() { return parseInt(this.getEvaluatedValue('__getWindow().innerHeight')); }; this.getWindowPageYOffset = function() { return this.getEvaluatedValue('__getWindow().pageYOffset'); }; this.getDocumentBodyOffsetHeight = function() { return this.getEvaluatedValue('__getDocument().body.offsetHeight'); }; this.getDocumentScrollTop = function() { return parseInt(this.getEvaluatedValue('__getDocument().documentElement.scrollTop')); }; // formula: y > 0 and y + h < ih this.isVisibleElementInViewport = function(elementPosition) { return (elementPosition.y > 0 && (elementPosition.y + elementPosition.h < this.getWindowInnerHeight())); }; this.isPageScrollEnded = function() { return (this.getWindowInnerHeight() + this.getWindowPageYOffset()) >= this.getDocumentBodyOffsetHeight; }; this.__escape = function(value) { var pos = value.indexOf("__escaped:"); if (pos === 0) return 'decodeURIComponent("' + value.substring(10) + '")'; else return 'decodeURIComponent("' + this.encodeURIComponent(value)[0] + '")'; }; // Added in 2024-01-08 this.encodeURI = function(s) { return [encodeURI(s), s]; }; // Added in 2024-01-08 this.decodeURI = function(s) { if (s instanceof Array && s.length == 2) { return s[1]; } else { return decodeURI(s); } }; // Added in 2024-01-08 this.encodeURIComponent = function(s) { return [encodeURIComponent(s), s]; }; // Added in 2024-01-08 this.decodeURIComponent = function(s) { if (s instanceof Array && s.length == 2) { return s[1]; } else { return decodeURIComponent(s); } }; this.prompt = function(s) { return this.getEvaluatedValue('prompt("' + s + '")'); }; this.confirm = function(s) { return this.getEvaluatedValue('(confirm("' + s + '") ? "true" : "false")'); }; this.setVendor = function(vendor) { var vendor = vendor.toLowerCase(); switch (vendor) { case "msedge": this.workingDirectory = SYS.getEnvString("PROGRAMFILES(X86)") + "\\Microsoft\\Edge\\Application"; this.binPath = SYS.getEnvString("PROGRAMFILES(X86)") + "\\Microsoft\\Edge\\Application\\msedge.exe"; break; case "chrome": this.workingDirectory = SYS.getEnvString("PROGRAMFILES") + "\\Google\\Chrome\\Application"; this.binPath = SYS.getEnvString("PROGRAMFILES") + "\\Google\\:installedDir\\Application\\chrome.exe"; break; case "chromium": this.workingDirectory = SYS.getEnvString("LOCALAPPDATA") + "\\Chromium\\Application"; this.binPath = SYS.getEnvString("LOCALAPPDATA") + "\\Chromium\\Application\\chrome.exe"; break; case "opera": this.workingDirectory = SYS.getEnvString("LOCALAPPDATA") + "\\Programs\\Opera"; this.binPath = SYS.getEnvString("LOCALAPPDATA") + "\\Programs\\Opera\\opera.exe"; break; } return this; }; this.vMouseClick = function(x, y) { Toolkit.sendClick(this.pageId.substring(0, 6), this.baseScreenX + x, this.baseScreenY + y, 1); }; this.vSendKeys = function(s) { Toolkit.sendKeys(this.pageId.substring(0, 6), s); }; this.mouseClick = function(x, y) { var screenPosition = this.getScreenPosition(); this.oAutoIt.callFunction("MouseMove", [screenPosition.x + this.baseScreenX + x, screenPosition.y + this.baseScreenY + y]); this.oAutoIt.callFunction("MouseClick", ["left"]); }; this.mouseWheelUp = function() { this.oAutoIt.callFunction("MouseWheel", ["up"]); }; this.mouseWheelDown = function() { this.oAutoIt.callFunction("MouseWheel", ["down"]); }; this.getReadyState = function() { return this.getEvaluatedValue("document.readyState"); }; this.getCookie = function() { return this.getEvaluatedValue("document.cookie"); }; this.getNumberOfSelectorAll = function(selector) { return parseInt(this.getEvaluatedValue('document.querySelectorAll("' + selector + '").length')); }; this.setValueOfSelectorAll = function(selector, s) { this.evaluate('document.querySelectorAll("' + selector + '").forEach(function(x){x.value = "' + s + '";})'); }; this.sendEnterKey = function() { this.evaluate('var ev=new KeyboardEvent("keydown",{bubbles:!0,cancelable:!0,keyCode:13});document.body.dispatchEvent(ev);'); }; this.getShadowRootSelector = function(selectors) { var s = "').shadowRoot.querySelector('"; return ".querySelector('" + selectors.join(s) + "')"; }; this.create(); }; ChromeObject.prototype = new STD.EventTarget(); ChromeObject.prototype.constructor = ChromeObject; exports.create = function(profileName) { return (new ChromeObject()).setProfile(profileName, null); }; exports.start = function(url, proxyPort, profileName, userDataDir, installedDir) { return (new ChromeObject()) .setProxyPort(proxyPort) .setProfile(profileName, installedDir) .setUserDataDir(userDataDir) .open(url) ; }; exports.startWithDebugging = function(url, proxy, profileName, debuggingPort) { return (new ChromeObject()) .setProxy(proxy) .setProfile(profileName, null) .setUserDataDir(null) .setDebuggingPort(debuggingPort) .open(url) ; }; exports.startWithDebuggingUA = function(url, proxy, profileName, debuggingPort) { return (new ChromeObject()) .setProxy(proxy) .setProfile(profileName, null) .setUserDataDir(null) .setDebuggingPort(debuggingPort) .addUserAgentsFromFile("data\\UserAgents.txt") .open(url) ; }; exports.startDebug = function(url, proxy, profileName, debuggingPort, isPreventProxy) { return (new ChromeObject()) .setProxy(proxy) .setProfile(profileName, null) .setUserDataDir(null) .setDebuggingPort(debuggingPort) .setIsPreventProxy(isPreventProxy) //.addUserAgentsFromFile("data\\Chrome.txt") //.addUserAgentsFromFile("data\\Edge.txt") //.addUserAgentsFromFile("data\\Safari.txt") .open(url) ; }; exports.startDebugInPrivate = function(url, proxy, profileName, debuggingPort, isPreventProxy) { return (new ChromeObject()) .setProxy(proxy) .setProfile(profileName, null) .setUserDataDir(null) .setDebuggingPort(debuggingPort) .setIsPreventProxy(isPreventProxy) .setInPrivate(true) //.addUserAgentsFromFile("data\\Chrome.txt") //.addUserAgentsFromFile("data\\Edge.txt") //.addUserAgentsFromFile("data\\Safari.txt") .open(url) ; }; exports.VERSIONINFO = "Chrome Web Browser Debugging Interface (chrome.js) version 0.4.9"; exports.AUTHOR = "abuse@catswords.net"; exports.global = global; exports.require = global.require;