Remove Playwright (#643)

This commit is contained in:
Mitchell Syer
2024-01-12 23:46:47 -05:00
committed by GitHub
parent 79eeb6d703
commit 28e4ac8dcb
13 changed files with 9 additions and 816 deletions

View File

@@ -10,7 +10,6 @@ dex2jar = "v64" # Stuck until https://github.com/ThexXTURBOXx/dex2jar/issues/27
rhino = "1.7.14"
settings = "1.0.0-RC"
twelvemonkeys = "3.9.4"
playwright = "1.28.0"
graphqlkotlin = "6.5.6"
xmlserialization = "0.86.2"
ktlint = "1.0.0"
@@ -108,9 +107,6 @@ zip4j = "net.lingala.zip4j:zip4j:2.11.5"
commonscompress = "org.apache.commons:commons-compress:1.24.0"
junrar = "com.github.junrar:junrar:7.5.5"
# CloudflareInterceptor
playwright = { module = "com.microsoft.playwright:playwright", version.ref = "playwright" }
# AES/CBC/PKCS7Padding Cypher provider
bouncycastle = "org.bouncycastle:bcprov-jdk18on:1.76"

View File

@@ -26,8 +26,6 @@ main() {
set -- "${POSITIONAL_ARGS[@]}"
OS="$1"
PLAYWRIGHT_VERSION="$(cat gradle/libs.versions.toml | grep -oP "playwright = \"\K([0-9\.]*)(?=\")")"
PLAYWRIGHT_REVISION="$(curl --silent "https://raw.githubusercontent.com/microsoft/playwright/v$PLAYWRIGHT_VERSION/packages/playwright-core/browsers.json" 2>&1 | grep -ozP "\"name\": \"chromium\",\n *\"revision\": \"\K[0-9]*")"
JAR="$(ls server/build/*.jar | tail -n1)"
RELEASE_NAME="$(echo "${JAR%.*}" | xargs basename)-$OS"
RELEASE_VERSION="$(tmp="${JAR%-*}"; echo "${tmp##*-}" | tr -d v)"
@@ -61,9 +59,6 @@ main() {
ELECTRON_URL="https://github.com/electron/electron/releases/download/$electron_version/$ELECTRON"
download_jre_and_electron
PLAYWRIGHT_PLATFORM="linux"
setup_playwright
RELEASE="$RELEASE_NAME.tar.gz"
make_linux_bundle
move_release_to_output_dir
@@ -77,9 +72,6 @@ main() {
ELECTRON_URL="https://github.com/electron/electron/releases/download/$electron_version/$ELECTRON"
download_jre_and_electron
PLAYWRIGHT_PLATFORM="mac"
setup_playwright
RELEASE="$RELEASE_NAME.zip"
make_macos_bundle
move_release_to_output_dir
@@ -93,9 +85,6 @@ main() {
ELECTRON_URL="https://github.com/electron/electron/releases/download/$electron_version/$ELECTRON"
download_jre_and_electron
PLAYWRIGHT_PLATFORM="mac-arm64"
setup_playwright
RELEASE="$RELEASE_NAME.zip"
make_macos_bundle
move_release_to_output_dir
@@ -109,9 +98,6 @@ main() {
ELECTRON_URL="https://github.com/electron/electron/releases/download/$electron_version/$ELECTRON"
download_jre_and_electron
PLAYWRIGHT_PLATFORM="win64"
setup_playwright
RELEASE="$RELEASE_NAME.zip"
make_windows_bundle
move_release_to_output_dir
@@ -129,9 +115,6 @@ main() {
ELECTRON_URL="https://github.com/electron/electron/releases/download/$electron_version/$ELECTRON"
download_jre_and_electron
PLAYWRIGHT_PLATFORM="win64"
setup_playwright
RELEASE="$RELEASE_NAME.zip"
make_windows_bundle
move_release_to_output_dir
@@ -295,11 +278,6 @@ make_windows_package() {
"$RELEASE_NAME/jre.wxs" "$RELEASE_NAME/electron.wxs" "$RELEASE_NAME/bin.wxs" -o "$RELEASE"
}
setup_playwright() {
mkdir "$RELEASE_NAME/bin"
curl -L "https://playwright.azureedge.net/builds/chromium/$PLAYWRIGHT_REVISION/chromium-$PLAYWRIGHT_PLATFORM.zip" -o "$RELEASE_NAME/bin/chromium.zip"
}
# Error handler
# set -u: Treat unset variables as an error when substituting.
# set -o pipefail: Prevents errors in pipeline from being masked.

View File

@@ -60,9 +60,6 @@ dependencies {
implementation(libs.commonscompress)
implementation(libs.junrar)
// CloudflareInterceptor
implementation(libs.playwright)
// AES/CBC/PKCS7Padding Cypher provider for zh.copymanga
implementation(libs.bouncycastle)

View File

@@ -1,212 +0,0 @@
/*
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package suwayomi.tachidesk.server.util;
import com.microsoft.playwright.impl.driver.Driver;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.*;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* Copy of <a href="https://github.com/microsoft/playwright-java/blob/8c0231b0f739656e8a86bc58fca9ee778ddc571b/driver-bundle/src/main/java/com/microsoft/playwright/impl/driver/jar/DriverJar.java">DriverJar</a>
* with support for pre-installing chromium and only supports chromium playwright
*/
public class DriverJar extends Driver {
private static final String PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD = "PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD";
private static final String SELENIUM_REMOTE_URL = "SELENIUM_REMOTE_URL";
static final String PLAYWRIGHT_NODEJS_PATH = "PLAYWRIGHT_NODEJS_PATH";
private final Path driverTempDir;
private Path preinstalledNodePath;
public DriverJar() throws IOException {
// Allow specifying custom path for the driver installation
// See https://github.com/microsoft/playwright-java/issues/728
String alternativeTmpdir = System.getProperty("playwright.driver.tmpdir");
String prefix = "playwright-java-";
driverTempDir = alternativeTmpdir == null
? Files.createTempDirectory(prefix)
: Files.createTempDirectory(Paths.get(alternativeTmpdir), prefix);
driverTempDir.toFile().deleteOnExit();
String nodePath = System.getProperty("playwright.nodejs.path");
if (nodePath != null) {
preinstalledNodePath = Paths.get(nodePath);
if (!Files.exists(preinstalledNodePath)) {
throw new RuntimeException("Invalid Node.js path specified: " + nodePath);
}
}
logMessage("created DriverJar: " + driverTempDir);
}
@Override
protected void initialize(Boolean installBrowsers) throws Exception {
if (preinstalledNodePath == null && env.containsKey(PLAYWRIGHT_NODEJS_PATH)) {
preinstalledNodePath = Paths.get(env.get(PLAYWRIGHT_NODEJS_PATH));
if (!Files.exists(preinstalledNodePath)) {
throw new RuntimeException("Invalid Node.js path specified: " + preinstalledNodePath);
}
} else if (preinstalledNodePath != null) {
// Pass the env variable to the driver process.
env.put(PLAYWRIGHT_NODEJS_PATH, preinstalledNodePath.toString());
}
extractDriverToTempDir();
logMessage("extracted driver from jar to " + driverPath());
if (installBrowsers)
installBrowsers(env);
}
private void installBrowsers(Map<String, String> env) throws IOException, InterruptedException {
String skip = env.get(PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD);
if (skip == null) {
skip = System.getenv(PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD);
}
if (skip != null && !"0".equals(skip) && !"false".equals(skip)) {
System.out.println("Skipping browsers download because `PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD` env variable is set");
return;
}
if (env.get(SELENIUM_REMOTE_URL) != null || System.getenv(SELENIUM_REMOTE_URL) != null) {
logMessage("Skipping browsers download because `SELENIUM_REMOTE_URL` env variable is set");
return;
}
Chromium.preinstall(platformDir());
Path driver = driverPath();
if (!Files.exists(driver)) {
throw new RuntimeException("Failed to find driver: " + driver);
}
ProcessBuilder pb = createProcessBuilder();
pb.command().add("install");
pb.command().add("chromium");
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
Process p = pb.start();
boolean result = p.waitFor(10, TimeUnit.MINUTES);
if (!result) {
p.destroy();
throw new RuntimeException("Timed out waiting for browsers to install");
}
if (p.exitValue() != 0) {
throw new RuntimeException("Failed to install browsers, exit code: " + p.exitValue());
}
}
private static boolean isExecutable(Path filePath) {
String name = filePath.getFileName().toString();
return name.endsWith(".sh") || name.endsWith(".exe") || !name.contains(".");
}
private FileSystem initFileSystem(URI uri) throws IOException {
try {
return FileSystems.newFileSystem(uri, Collections.emptyMap());
} catch (FileSystemAlreadyExistsException e) {
return null;
}
}
public static URI getDriverResourceURI() throws URISyntaxException {
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
return classloader.getResource("driver/" + platformDir()).toURI();
}
void extractDriverToTempDir() throws URISyntaxException, IOException {
URI originalUri = getDriverResourceURI();
URI uri = maybeExtractNestedJar(originalUri);
// Create zip filesystem if loading from jar.
try (FileSystem fileSystem = "jar".equals(uri.getScheme()) ? initFileSystem(uri) : null) {
Path srcRoot = Paths.get(uri);
// jar file system's .relativize gives wrong results when used with
// spring-boot-maven-plugin, convert to the default filesystem to
// have predictable results.
// See https://github.com/microsoft/playwright-java/issues/306
Path srcRootDefaultFs = Paths.get(srcRoot.toString());
Files.walk(srcRoot).forEach(fromPath -> {
if (preinstalledNodePath != null) {
String fileName = fromPath.getFileName().toString();
if ("node.exe".equals(fileName) || "node".equals(fileName)) {
return;
}
}
Path relative = srcRootDefaultFs.relativize(Paths.get(fromPath.toString()));
Path toPath = driverTempDir.resolve(relative.toString());
try {
if (Files.isDirectory(fromPath)) {
Files.createDirectories(toPath);
} else {
Files.copy(fromPath, toPath);
if (isExecutable(toPath)) {
toPath.toFile().setExecutable(true, true);
}
}
toPath.toFile().deleteOnExit();
} catch (IOException e) {
throw new RuntimeException("Failed to extract driver from " + uri + ", full uri: " + originalUri, e);
}
});
}
}
private URI maybeExtractNestedJar(final URI uri) throws URISyntaxException {
if (!"jar".equals(uri.getScheme())) {
return uri;
}
final String JAR_URL_SEPARATOR = "!/";
String[] parts = uri.toString().split("!/");
if (parts.length != 3) {
return uri;
}
String innerJar = String.join(JAR_URL_SEPARATOR, parts[0], parts[1]);
URI jarUri = new URI(innerJar);
try (FileSystem fs = FileSystems.newFileSystem(jarUri, Collections.emptyMap())) {
Path fromPath = Paths.get(jarUri);
Path toPath = driverTempDir.resolve(fromPath.getFileName().toString());
Files.copy(fromPath, toPath);
toPath.toFile().deleteOnExit();
return new URI("jar:" + toPath.toUri() + JAR_URL_SEPARATOR + parts[2]);
} catch (IOException e) {
throw new RuntimeException("Failed to extract driver's nested .jar from " + jarUri + "; full uri: " + uri, e);
}
}
private static String platformDir() {
String name = System.getProperty("os.name").toLowerCase();
String arch = System.getProperty("os.arch").toLowerCase();
if (name.contains("windows")) {
return "win32_x64";
}
if (name.contains("linux")) {
if (arch.equals("aarch64")) {
return "linux-arm64";
} else {
return "linux";
}
}
if (name.contains("mac os x")) {
return "mac";
}
throw new RuntimeException("Unexpected os.name value: " + name);
}
@Override
protected Path driverDir() {
return driverTempDir;
}
}

View File

@@ -1,24 +1,11 @@
package eu.kanade.tachiyomi.network.interceptor
import com.microsoft.playwright.Browser
import com.microsoft.playwright.BrowserType.LaunchOptions
import com.microsoft.playwright.Page
import com.microsoft.playwright.Playwright
import com.microsoft.playwright.PlaywrightException
import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.network.interceptor.CFClearance.resolveWithWebView
import mu.KotlinLogging
import okhttp3.Cookie
import okhttp3.HttpUrl
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.Response
import suwayomi.tachidesk.server.ServerConfig
import suwayomi.tachidesk.server.serverConfig
import uy.kohesive.injekt.injectLazy
import java.io.IOException
import kotlin.time.Duration.Companion.seconds
import kotlin.time.DurationUnit
class CloudflareInterceptor : Interceptor {
private val logger = KotlinLogging.logger {}
@@ -38,7 +25,7 @@ class CloudflareInterceptor : Interceptor {
return originalResponse
}
throw IOException("playwrite is diabled for v0.6.7")
throw IOException("Cloudflare bypass currently disabled ")
logger.debug { "Cloudflare anti-bot is on, CloudflareInterceptor is kicking in..." }
@@ -46,7 +33,7 @@ class CloudflareInterceptor : Interceptor {
originalResponse.close()
network.cookieStore.remove(originalRequest.url.toUri())
val request = resolveWithWebView(originalRequest)
val request = originalRequest // resolveWithWebView(originalRequest)
chain.proceed(request)
} catch (e: Exception) {
@@ -71,7 +58,7 @@ object CFClearance {
private val logger = KotlinLogging.logger {}
private val network: NetworkHelper by injectLazy()
init {
/*init {
// Fix the default DriverJar issue by providing our own implementation
// ref: https://github.com/microsoft/playwright-java/issues/1138
System.setProperty("playwright.driver.impl", "suwayomi.tachidesk.server.util.DriverJar")
@@ -140,11 +127,12 @@ object CFClearance {
return originalRequest.newBuilder()
.header("Cookie", newCookies.joinToString("; ") { "${it.name}=${it.value}" })
.build()
}
}*/
@Suppress("UNREACHABLE_CODE")
fun getWebViewUserAgent(): String {
return try {
return "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
/*return try {
throw PlaywrightException("playwrite is diabled for v0.6.7")
Playwright.create().use { playwright ->
@@ -162,10 +150,10 @@ object CFClearance {
} catch (e: PlaywrightException) {
// Playwright might fail on headless environments like docker
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
}
}*/
}
private fun getCookies(
/*private fun getCookies(
page: Page,
url: String,
): List<Cookie> {
@@ -235,7 +223,7 @@ object CFClearance {
if (success) return true
}
return false
}
}*/
private class CloudflareBypassException : Exception()
}

View File

@@ -1,60 +0,0 @@
package suwayomi.tachidesk.server.util
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.contentOrNull
import kotlinx.serialization.json.decodeFromStream
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import net.harawata.appdirs.AppDirsFactory
import java.nio.file.FileSystems
import java.nio.file.Files
import java.nio.file.StandardCopyOption
import kotlin.io.path.Path
import kotlin.io.path.absolutePathString
import kotlin.io.path.createDirectories
import kotlin.io.path.exists
import kotlin.io.path.notExists
import kotlin.streams.asSequence
object Chromium {
@OptIn(ExperimentalSerializationApi::class)
@JvmStatic
fun preinstall(platformDir: String) {
val loader = Thread.currentThread().contextClassLoader
val resource = loader.getResource("driver/$platformDir/package/browsers.json") ?: return
val json =
resource.openStream().use {
Json.decodeFromStream<JsonObject>(it)
}
val revision =
json["browsers"]?.jsonArray
?.find { it.jsonObject["name"]?.jsonPrimitive?.contentOrNull == "chromium" }
?.jsonObject
?.get("revision")
?.jsonPrimitive
?.contentOrNull
?: return
val playwrightDir = AppDirsFactory.getInstance().getUserDataDir("ms-playwright", null, null)
val chromiumZip = Path(".").resolve("bin/chromium.zip")
val chromePath = Path(playwrightDir).resolve("chromium-$revision")
if (chromePath.exists() || chromiumZip.notExists()) return
chromePath.createDirectories()
FileSystems.newFileSystem(chromiumZip, null as ClassLoader?).use {
val src = it.getPath("/")
Files.walk(src)
.asSequence()
.forEach { source ->
Files.copy(
source,
chromePath.resolve(source.absolutePathString().removePrefix("/")),
StandardCopyOption.REPLACE_EXISTING,
)
}
}
}
}

View File

@@ -1,28 +0,0 @@
(function () {
const ORIGINAL_CANVAS = HTMLCanvasElement.prototype[name];
Object.defineProperty(HTMLCanvasElement.prototype, name, {
"value": function () {
var shift = {
'r': Math.floor(Math.random() * 10) - 5,
'g': Math.floor(Math.random() * 10) - 5,
'b': Math.floor(Math.random() * 10) - 5,
'a': Math.floor(Math.random() * 10) - 5
};
var width = this.width,
height = this.height,
context = this.getContext("2d");
var imageData = context.getImageData(0, 0, width, height);
for (var i = 0; i < height; i++) {
for (var j = 0; j < width; j++) {
var n = ((i * (width * 4)) + (j * 4));
imageData.data[n + 0] = imageData.data[n + 0] + shift.r;
imageData.data[n + 1] = imageData.data[n + 1] + shift.g;
imageData.data[n + 2] = imageData.data[n + 2] + shift.b;
imageData.data[n + 3] = imageData.data[n + 3] + shift.a;
}
}
context.putImageData(imageData, 0, 0);
return ORIGINAL_CANVAS.apply(this, arguments);
}
});
})(this);

View File

@@ -1,52 +0,0 @@
Object.defineProperty(window, 'chrome', {
value: new Proxy(window.chrome, {
has: (target, key) => true,
get: (target, key) => {
return {
app: {
isInstalled: false,
},
webstore: {
onInstallStageChanged: {},
onDownloadProgress: {},
},
runtime: {
PlatformOs: {
MAC: 'mac',
WIN: 'win',
ANDROID: 'android',
CROS: 'cros',
LINUX: 'linux',
OPENBSD: 'openbsd',
},
PlatformArch: {
ARM: 'arm',
X86_32: 'x86-32',
X86_64: 'x86-64',
},
PlatformNaclArch: {
ARM: 'arm',
X86_32: 'x86-32',
X86_64: 'x86-64',
},
RequestUpdateCheckStatus: {
THROTTLED: 'throttled',
NO_UPDATE: 'no_update',
UPDATE_AVAILABLE: 'update_available',
},
OnInstalledReason: {
INSTALL: 'install',
UPDATE: 'update',
CHROME_UPDATE: 'chrome_update',
SHARED_MODULE_UPDATE: 'shared_module_update',
},
OnRestartRequiredReason: {
APP_UPDATE: 'app_update',
OS_UPDATE: 'os_update',
PERIODIC: 'periodic',
},
},
}
}
})
});

View File

@@ -1,203 +0,0 @@
(function () {
const plugin0 = Object.create(Plugin.prototype);
const mimeType0 = Object.create(MimeType.prototype);
const mimeType1 = Object.create(MimeType.prototype);
Object.defineProperties(mimeType0, {
type: {
get: () => 'application/pdf',
},
suffixes: {
get: () => 'pdf',
},
});
Object.defineProperties(mimeType1, {
type: {
get: () => 'text/pdf',
},
suffixes: {
get: () => 'pdf',
},
});
Object.defineProperties(plugin0, {
name: {
get: () => 'Chrome PDF Viewer',
},
description: {
get: () => 'Portable Document Format',
},
0: {
get: () => {
return mimeType0;
},
},
1: {
get: () => {
return mimeType1;
},
},
length: {
get: () => 2,
},
filename: {
get: () => 'internal-pdf-viewer',
},
});
const plugin1 = Object.create(Plugin.prototype);
Object.defineProperties(plugin1, {
name: {
get: () => 'Chromium PDF Viewer',
},
description: {
get: () => 'Portable Document Format',
},
0: {
get: () => {
return mimeType0;
},
},
1: {
get: () => {
return mimeType1;
},
},
length: {
get: () => 2,
},
filename: {
get: () => 'internal-pdf-viewer',
},
});
const plugin2 = Object.create(Plugin.prototype);
Object.defineProperties(plugin2, {
name: {
get: () => 'Microsoft Edge PDF Viewer',
},
description: {
get: () => 'Portable Document Format',
},
0: {
get: () => {
return mimeType0;
},
},
1: {
get: () => {
return mimeType1;
},
},
length: {
get: () => 2,
},
filename: {
get: () => 'internal-pdf-viewer',
},
});
const plugin3 = Object.create(Plugin.prototype);
Object.defineProperties(plugin3, {
name: {
get: () => 'PDF Viewer',
},
description: {
get: () => 'Portable Document Format',
},
0: {
get: () => {
return mimeType0;
},
},
1: {
get: () => {
return mimeType1;
},
},
length: {
get: () => 2,
},
filename: {
get: () => 'internal-pdf-viewer',
},
});
const plugin4 = Object.create(Plugin.prototype);
Object.defineProperties(plugin4, {
name: {
get: () => 'WebKit built-in PDF',
},
description: {
get: () => 'Portable Document Format',
},
0: {
get: () => {
return mimeType0;
},
},
1: {
get: () => {
return mimeType1;
},
},
length: {
get: () => 2,
},
filename: {
get: () => 'internal-pdf-viewer',
},
});
const pluginArray = Object.create(PluginArray.prototype);
pluginArray['0'] = plugin0;
pluginArray['1'] = plugin1;
pluginArray['2'] = plugin2;
pluginArray['3'] = plugin3;
pluginArray['4'] = plugin4;
let refreshValue;
Object.defineProperties(pluginArray, {
length: {
get: () => 5,
},
item: {
value: (index) => {
if (index > 4294967295) {
index = index % 4294967296;
}
switch (index) {
case 0:
return plugin3;
case 1:
return plugin0;
case 2:
return plugin1;
case 3:
return plugin2;
case 4:
return plugin4;
default:
break;
}
},
},
refresh: {
get: () => {
return refreshValue;
},
set: (value) => {
refreshValue = value;
},
},
});
Object.defineProperty(Object.getPrototypeOf(navigator), 'plugins', {
get: () => {
return pluginArray;
},
});
})();

View File

@@ -1,170 +0,0 @@
(function () {
window.chrome = {};
window.chrome.app = {
InstallState: {
DISABLED: 'disabled',
INSTALLED: 'installed',
NOT_INSTALLED: 'not_installed',
},
RunningState: {
CANNOT_RUN: 'cannot_run',
READY_TO_RUN: 'ready_to_run',
RUNNING: 'running',
},
getDetails: () => {
'[native code]';
},
getIsInstalled: () => {
'[native code]';
},
installState: () => {
'[native code]';
},
get isInstalled() {
return false;
},
runningState: () => {
'[native code]';
},
};
window.chrome.runtime = {
OnInstalledReason: {
CHROME_UPDATE: 'chrome_update',
INSTALL: 'install',
SHARED_MODULE_UPDATE: 'shared_module_update',
UPDATE: 'update',
},
OnRestartRequiredReason: {
APP_UPDATE: 'app_update',
OS_UPDATE: 'os_update',
PERIODIC: 'periodic',
},
PlatformArch: {
ARM: 'arm',
ARM64: 'arm64',
MIPS: 'mips',
MIPS64: 'mips64',
X86_32: 'x86-32',
X86_64: 'x86-64',
},
PlatformNaclArch: {
ARM: 'arm',
MIPS: 'mips',
MIPS64: 'mips64',
X86_32: 'x86-32',
X86_64: 'x86-64',
},
PlatformOs: {
ANDROID: 'android',
CROS: 'cros',
FUCHSIA: 'fuchsia',
LINUX: 'linux',
MAC: 'mac',
OPENBSD: 'openbsd',
WIN: 'win',
},
RequestUpdateCheckStatus: {
NO_UPDATE: 'no_update',
THROTTLED: 'throttled',
UPDATE_AVAILABLE: 'update_available',
},
connect() {
'[native code]';
},
sendMessage() {
'[native code]';
},
id: undefined,
};
let startE = Date.now();
window.chrome.csi = function () {
'[native code]';
return {
startE: startE,
onloadT: startE + 281,
pageT: 3947.235,
tran: 15,
};
};
window.chrome.loadTimes = function () {
'[native code]';
return {
get requestTime() {
return startE / 1000;
},
get startLoadTime() {
return startE / 1000;
},
get commitLoadTime() {
return startE / 1000 + 0.324;
},
get finishDocumentLoadTime() {
return startE / 1000 + 0.498;
},
get finishLoadTime() {
return startE / 1000 + 0.534;
},
get firstPaintTime() {
return startE / 1000 + 0.437;
},
get firstPaintAfterLoadTime() {
return 0;
},
get navigationType() {
return 'Other';
},
get wasFetchedViaSpdy() {
return true;
},
get wasNpnNegotiated() {
return true;
},
get npnNegotiatedProtocol() {
return 'h3';
},
get wasAlternateProtocolAvailable() {
return false;
},
get connectionInfo() {
return 'h3';
},
};
};
})();
// Bypass OOPIF test
(function performance_memory() {
const jsHeapSizeLimitInt = 4294705152;
const total_js_heap_size = 35244183;
const used_js_heap_size = [
17632315, 17632315, 17632315, 17634847, 17636091, 17636751,
];
let counter = 0;
let MemoryInfoProto = Object.getPrototypeOf(performance.memory);
Object.defineProperties(MemoryInfoProto, {
jsHeapSizeLimit: {
get: () => {
return jsHeapSizeLimitInt;
},
},
totalJSHeapSize: {
get: () => {
return total_js_heap_size;
},
},
usedJSHeapSize: {
get: () => {
if (counter > 5) {
counter = 0;
}
return used_js_heap_size[counter++];
},
},
});
})();

View File

@@ -1,3 +0,0 @@
Object.defineProperty(navigator, 'maxTouchPoints', {
get: () => 1
});

View File

@@ -1,33 +0,0 @@
// https://github.com/microlinkhq/browserless/blob/master/packages/goto/src/evasions/navigator-permissions.js
if (!window.Notification) {
window.Notification = {
permission: 'denied'
}
}
const originalQuery = window.navigator.permissions.query
window.navigator.permissions.__proto__.query = parameters =>
parameters.name === 'notifications'
? Promise.resolve({state: window.Notification.permission})
: originalQuery(parameters)
const oldCall = Function.prototype.call
function call() {
return oldCall.apply(this, arguments)
}
Function.prototype.call = call
const nativeToStringFunctionString = Error.toString().replace(/Error/g, 'toString')
const oldToString = Function.prototype.toString
function functionToString() {
if (this === window.navigator.permissions.query) {
return 'function query() { [native code] }'
}
if (this === functionToString) {
return nativeToStringFunctionString
}
return oldCall.call(oldToString, this)
}
// eslint-disable-next-line
Function.prototype.toString = functionToString

View File

@@ -1,5 +0,0 @@
Object.defineProperty(Navigator.prototype, 'webdriver', {
get() {
return false;
},
});