Skip to content
This repository has been archived by the owner on Jul 22, 2024. It is now read-only.

Commit

Permalink
Add user agent override list support. (fixes #488)
Browse files Browse the repository at this point in the history
  • Loading branch information
Randall Barker committed Nov 19, 2018
1 parent 8b0085a commit 3d6047f
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

package org.mozilla.vrbrowser.browser;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Rect;
Expand Down Expand Up @@ -76,6 +77,7 @@ public static SessionStore get() {
private LinkedList<SessionChangeListener> mSessionChangeListeners;
private LinkedList<GeckoSession.TextInputDelegate> mTextInputListeners;
private LinkedList<GeckoSession.PromptDelegate> mPromptListeners;
private UserAgentOverride mUserAgentOverride;

public interface SessionChangeListener {
void onNewSession(GeckoSession aSession, int aId);
Expand Down Expand Up @@ -175,6 +177,10 @@ public void setContext(Context aContext, Bundle aExtras) {

mContext = aContext;
mPrefs = PreferenceManager.getDefaultSharedPreferences(mContext);
if (mUserAgentOverride == null) {
mUserAgentOverride = new UserAgentOverride();
mUserAgentOverride.loadOverridesFromAssets((Activity)aContext, aContext.getString(R.string.user_agent_override_file));
}
}

public void dumpAllState(Integer sessionId) {
Expand Down Expand Up @@ -858,6 +864,7 @@ public void onCanGoForward(GeckoSession aSession, boolean aCanGoForward) {
@Override
public @Nullable GeckoResult<AllowOrDeny> onLoadRequest(@NonNull GeckoSession aSession, @NonNull LoadRequest aRequest) {
final GeckoResult<AllowOrDeny> result = new GeckoResult<>();
aSession.getSettings().setString(GeckoSessionSettings.USER_AGENT_OVERRIDE, mUserAgentOverride.lookupOverride(aRequest.uri));
if (PRIVATE_BROWSING_URI.equalsIgnoreCase(aRequest.uri)) {
switchPrivateMode();
result.complete(AllowOrDeny.ALLOW);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package org.mozilla.vrbrowser.browser;

import android.app.Activity;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

public class UserAgentOverride {
private final static String LOGTAG = "VRB";
private static final String NO_OVERRIDE_FOUND = "NO OVERRIDE USER AGENT FOUND";
private ArrayMap<String, String> mOverrideMap;
private ArrayMap<String, String> mOverrideCache;
public UserAgentOverride() {
mOverrideMap = new ArrayMap<>();
mOverrideCache = new ArrayMap<>();
}

public void loadOverridesFromAssets(Activity aActivity, String aFileName) {
String json = null;
try {
InputStream is = aActivity.getAssets().open(aFileName);
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
json = new String(buffer, "UTF-8");
importJSONData(json);
} catch (IOException e) {
Log.e(LOGTAG, "Failed reading user agent override file: " + aFileName + " Error: " + e.getMessage());
e.printStackTrace();
}
}

public String lookupOverride(final String aUri) {
Log.d(LOGTAG, "lookupOverride for: " + aUri);
URI uri = URI.create(aUri);
String fullDomain = uri.getHost();
if (fullDomain == null) {
return null;
}

fullDomain = fullDomain.toLowerCase();

String override = mOverrideCache.get(fullDomain);

if (override != null) {
Log.d(LOGTAG, "Found override:" + override);
return override.equals(NO_OVERRIDE_FOUND) ? null : override;
}

List<String> domains = Arrays.asList(fullDomain.split("\\."));
final int domainCount = domains.size();
String[] checkedDomains = new String[domainCount];

for (int ix = 0; ix < domainCount; ix++) {
String domain = TextUtils.join(".", domains.subList(ix, domainCount));
checkedDomains[ix] = domain;
override = mOverrideCache.get(domain);
if (override != null) {
Log.d(LOGTAG, "found cached override: " + override);
addToCache(checkedDomains, override);
return override.equals(NO_OVERRIDE_FOUND) ? null : override;
}
String domainHash = hashDomain(domain);
if (domainHash == null) {
Log.d(LOGTAG, "Failed to hash domain" + domain);
return null;
}
Log.d(LOGTAG, "hash: " + domainHash);
override = mOverrideMap.get(domainHash);
if (override != null) {
Log.d(LOGTAG, "found override from hash: " + override);
addToCache(checkedDomains, override);
return override;
}
}
addToCache(checkedDomains, NO_OVERRIDE_FOUND);
return null;
}

private void addToCache(String[] aDomains, String aOverride) {
for (String domain: aDomains) {
if (domain == null) {
Log.d(LOGTAG, "Found null domain in checked list");
continue;
} else {
Log.d(LOGTAG, domain + " override: " + aOverride);
}
mOverrideCache.put(domain, aOverride);
}
}

private String hashDomain(String aDomain) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-512");
byte[] digest = md.digest(aDomain.getBytes());
StringBuilder sb = new StringBuilder();
for (int value: digest) {
sb.append(Integer.toString((value & 0xff) + 0x100, 16).substring(1));
}

return sb.toString().toUpperCase();
} catch (NoSuchAlgorithmException e) {
Log.e(LOGTAG, "Error while trying to hash domain: " + e.getMessage());
}
return null;
}

private void importJSONData(final String aData) {
try {
JSONObject json = new JSONObject(aData);
Iterator<String> iter = json.keys();
while (iter.hasNext()) {
String key = iter.next();
try {
String value = json.getString(key);
Log.d(LOGTAG, "User agent override: " + key + " -> " + value);
mOverrideMap.put(key, value);
} catch (JSONException e) {
Log.e(LOGTAG, "Failed to find UA Override while parsing file for key: " + key);
}
}

} catch (JSONException e) {
e.printStackTrace();
}
}
}
5 changes: 5 additions & 0 deletions app/src/main/assets/userAgentOverride.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"AE0755740E4354AC67025056E775AD06D8A529AE4F37244FBB02D72199E2C780311E47AA9895079B980EC4BFA676F1F39C4AB41EA995C524E52BDE9A73623DA2": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12) AppleWebKit/602.1.21 (KHTML, like Gecko) Version/9.2 Safari/602.1.21",
"E6137B4C2F49A3917C2C90A50FB270A5EEBB962F2C72344AE2E29E321BB21891E5CA4FEC06CAE78E14F4A8510473E934234E9EC3F60E8415F5F6DA754C55B9B1": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12) AppleWebKit/602.1.21 (KHTML, like Gecko) Version/9.2 Safari/602.1.21",
"A5593B10E239D568ECB4A1F5F9980CC00DA2D6B14EF6696760481EEDA8933811A96A7A5ECC5D8EEBC40C427AE9AEDA9025925DB07217E375875F0FB1297216A5": "Mozilla/5.0 (X11; Linux x86_64; rv:65.0) Gecko/20100101 Firefox/65.0 SamsungBrowser"
}
1 change: 1 addition & 0 deletions app/src/main/res/values/non_L10n.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
<string name="app_permission_name" translatable="false">org.mozilla.vrbrowser.CRASH_RECEIVER_PERMISSION</string>
<string name="developer_options_by" translatable="false">x</string>
<string name="crash_app_name" translatable="false">FirefoxReality</string>
<string name="user_agent_override_file" translatable="false">userAgentOverride.json</string>

<!-- SEARCH ENGINES -->
<string name="geolocation_api_url" translatable="false">https://location.services.mozilla.com/v1/country</string>
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ buildscript {
ext.geckoNightly = [
// GeckoView versions can be found here:
// https://maven.mozilla.org/?prefix=maven2/org/mozilla/geckoview/
version: '65.0.20181110100141'
version: '65.0.20181119100115'
]

// Android components version
Expand Down

0 comments on commit 3d6047f

Please sign in to comment.