/* * jBrowserDriver (TM) * Copyright (C) 2014-2016 Machine Publishers, LLC and the jBrowserDriver contributors * https://github.com/MachinePublishers/jBrowserDriver * * 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 com.machinepublishers.jbrowserdriver; import java.util.LinkedHashMap; import java.util.Map; /** * Browser user agent and related properties. * * @see RequestHeaders */ public class UserAgent { public static enum Family { /** * Firefox and Tor browsers */ MOZILLA, /** * Safari and Chrome browsers */ WEBKIT } private static final String baseNavigator; static { Map<String, String> baseNavigatorTmp = new LinkedHashMap<String, String>(); baseNavigatorTmp.put("vibrate", "function(){return true;}"); baseNavigatorTmp.put("vibrate.toString", "function(){return 'function vibrate() { [native code] }';}"); baseNavigatorTmp.put("javaEnabled", "function(){return false;}"); baseNavigatorTmp.put("javaEnabled.toString", "function(){return 'function javaEnabled() { [native code] }';}"); baseNavigatorTmp.put("sendBeacon", "function(){return false;}"); baseNavigatorTmp.put("sendBeacon.toString", "function(){return 'function sendBeacon() { [native code] }';}"); baseNavigatorTmp.put("registerProtocolHandler", "function(){}"); baseNavigatorTmp.put("registerProtocolHandler.toString", "function(){return 'function registerProtocolHandler() { [native code] }';}"); baseNavigatorTmp.put("registerContentHandler", "function(){}"); baseNavigatorTmp.put("registerContentHandler.toString", "function(){return 'function registerContentHandler() { [native code] }';}"); baseNavigatorTmp.put("taintEnabled", "function(){return false;}"); baseNavigatorTmp.put("taintEnabled.toString", "function(){return 'function taintEnabled() { [native code] }';}"); baseNavigatorTmp.put("mimeTypes", "navigator.mimeTypes"); baseNavigatorTmp.put("mimeTypes.toString", "function(){return '[object MimeTypeArray]';}"); baseNavigatorTmp.put("plugins", "navigator.plugins"); baseNavigatorTmp.put("plugins.toString", "function(){return '[object PluginArray]';}"); baseNavigatorTmp.put("doNotTrack", "'unspecified'"); baseNavigatorTmp.put("cookieEnabled", "true"); baseNavigatorTmp.put("onLine", "true"); baseNavigator = buildNavigator(baseNavigatorTmp); } private static final String mozNavigator; static { Map<String, String> mozNavigatorTmp = new LinkedHashMap<String, String>(); mozNavigatorTmp.put("mozId", "null"); mozNavigatorTmp.put("mozPay", "null"); mozNavigatorTmp.put("mozAlarms", "null"); mozNavigatorTmp.put("mozContacts", new StringBuilder() .append("{toString:function(){return '[object ContactManager]';},") .append("find:function(){return new Object();},") .append("getAll:function(){return new Object();},") .append("clear:function(){return new Object();},") .append("save:function(){return new Object();},") .append("remove:function(){return new Object();},") .append("getRevision:function(){return new Object();},") .append("getCount:function(){return new Object();},") .append("oncontactchange:null,") .append("addEventListener:function(){return new Object();},") .append("removeEventListener:function(){return new Object();},") .append("dispatchEvent:function(){return new Object();},") .append("}").toString()); mozNavigatorTmp.put("mozPhoneNumberService", "''"); mozNavigatorTmp.put("mozApps", new StringBuilder() .append("{toString:function(){return '[xpconnect wrapped (nsISupports, mozIDOMApplicationRegistry, mozIDOMApplicationRegistry2)]';},") .append("QueryInterface:function(){return new Object();},") .append("install:function(){return new Object();},") .append("getSelf:function(){return new Object();},") .append("checkInstalled:function(){return new Object();},") .append("getInstalled:function(){return new Object();},") .append("installPackage:function(){return new Object();},") .append("mgmt:null,") .append("}").toString()); mozNavigatorTmp.put("mozTCPSocket", "null"); mozNavigatorTmp.put("mozIsLocallyAvailable", "function(){return false;}"); mozNavigatorTmp.put("mozIsLocallyAvailable.toString", "function(){return 'function mozIsLocallyAvailable() { [native code] }';}"); mozNavigatorTmp.put("vendorSub", "''"); mozNavigatorTmp.put("productSub", "'20100101'"); mozNavigatorTmp.put("buildID", "'20100101'"); mozNavigatorTmp.put("appCodeName", "'Mozilla'"); mozNavigatorTmp.put("appName", "'Netscape'"); mozNavigatorTmp.put("product", "'Gecko'"); mozNavigator = buildNavigator(mozNavigatorTmp); } private static final String webkitNavigator; static { Map<String, String> webkitNavigatorTmp = new LinkedHashMap<String, String>(); webkitNavigatorTmp.put("vendorSub", "''"); webkitNavigatorTmp.put("productSub", "'20030107'"); webkitNavigatorTmp.put("buildID", "'20030107'"); webkitNavigatorTmp.put("appCodeName", "'Mozilla'"); webkitNavigatorTmp.put("appName", "'Netscape'"); webkitNavigatorTmp.put("product", "'Gecko'"); webkitNavigator = buildNavigator(webkitNavigatorTmp); } /** * Tor Browser * * @see RequestHeaders#TOR */ public static UserAgent TOR = new UserAgent( Family.MOZILLA, "", "Win32", "Windows NT 6.1", "5.0 (Windows)", "Mozilla/5.0 (Windows NT 6.1; rv:38.0) Gecko/20100101 Firefox/38.0"); /** * Chrome browser * * @see RequestHeaders#CHROME */ public static UserAgent CHROME = new UserAgent( Family.WEBKIT, "Google Inc.", "Win32", "Windows NT 6.1", "5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36", "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36"); private final String script; private final String userAgentString; /** * @param family * Category of browsers which share similar properties * @param vendor * Property of the navigator object * @param platform * Property of the navigator object * @param oscpu * Property of the navigator object * @param appVersion * Property of the navigator object * @param userAgentString * Property of the navigator object and also sent on headers */ public UserAgent(Family family, String vendor, String platform, String oscpu, String appVersion, String userAgentString) { this(family, "en-US", vendor, platform, oscpu, appVersion, userAgentString); } /** * @param family * Category of browsers which share similar properties * @param language * Language property of the navigator object * @param vendor * Property of the navigator object * @param platform * Property of the navigator object * @param oscpu * Property of the navigator object * @param appVersion * Property of the navigator object * @param userAgentString * Property of the navigator object and also sent on headers */ public UserAgent(Family family, String language, String vendor, String platform, String oscpu, String appVersion, String userAgentString) { StringBuilder builder = new StringBuilder(); builder.append(baseNavigator); if (family == Family.MOZILLA) { builder.append(mozNavigator); } else if (family == Family.WEBKIT) { builder.append(webkitNavigator); } Map<String, String> navigator = new LinkedHashMap<String, String>(); navigator.put("language", "'" + (language == null ? "" : language) + "'"); navigator.put("vendor", "'" + (vendor == null ? "" : vendor) + "'"); navigator.put("platform", "'" + (platform == null ? "" : platform) + "'"); navigator.put("oscpu", "'" + (oscpu == null ? "" : oscpu) + "'"); navigator.put("appVersion", "'" + (appVersion == null ? "" : appVersion) + "'"); navigator.put("userAgent", "'" + (userAgentString == null ? "" : userAgentString) + "'"); builder.append(buildNavigator(navigator)); this.userAgentString = userAgentString; script = builder.toString(); } private static String buildNavigator(Map<String, String> navigator) { StringBuilder builder = new StringBuilder(); for (Map.Entry<String, String> entry : navigator.entrySet()) { if (entry.getKey().contains(".")) { int lastDot = entry.getKey().lastIndexOf("."); String parent = entry.getKey().substring(0, lastDot); String child = entry.getKey().substring(lastDot + 1); builder.append("Object.defineProperty(window.navigator.").append(parent).append(",'").append(child).append("',"); builder.append("{value:").append(entry.getValue()).append("});"); } else { builder.append("try{"); builder.append("Object.defineProperty(window.navigator,'").append(entry.getKey()); builder.append("',{value:").append(entry.getValue()); builder.append("});"); builder.append("}catch(e){"); builder.append("window.navigator = Object.create(navigator, {" + entry.getKey()); builder.append(":{value:").append(entry.getValue()).append("}"); builder.append("});"); builder.append("}"); } } return builder.toString(); } String userAgentString() { return userAgentString; } String script() { return script; } }