aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAllan Wang <me@allanwang.ca>2017-08-15 19:53:57 -0700
committerGitHub <noreply@github.com>2017-08-15 19:53:57 -0700
commit2eaad9b72746d57c187d2ded7f40d803f88dfcee (patch)
treebab40fa1cd7e9fd4bba8fd59b562207010fc58ba
parent19ec9b543e15fe453b576f1b38994b3f8692054f (diff)
downloadfrost-2eaad9b72746d57c187d2ded7f40d803f88dfcee.tar.gz
frost-2eaad9b72746d57c187d2ded7f40d803f88dfcee.tar.bz2
frost-2eaad9b72746d57c187d2ded7f40d803f88dfcee.zip
Enhancement/url redirect manager (#182)
* Initial blacklist * Move js checks to java * Optimize imports and clean up request interceptor
-rw-r--r--app/src/main/assets/js/click_a.js15
-rw-r--r--app/src/main/assets/js/click_a.min.js8
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt5
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt10
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostRequestInterceptor.kt44
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostUrlOverlayValidator.kt48
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt7
7 files changed, 93 insertions, 44 deletions
diff --git a/app/src/main/assets/js/click_a.js b/app/src/main/assets/js/click_a.js
index 9f4ddc38..24a08f56 100644
--- a/app/src/main/assets/js/click_a.js
+++ b/app/src/main/assets/js/click_a.js
@@ -15,17 +15,16 @@ if (!window.hasOwnProperty('frost_click_a')) {
if (element.tagName !== 'A') element = element.parentNode;
//Notifications is two layers under
if (element.tagName !== 'A') element = element.parentNode;
- if (element.tagName === 'A' && element.getAttribute('href') !== '#') {
- var url = element.getAttribute('href');
- if (url.includes('photoset_token')) return;
-
-
+ if (element.tagName === 'A') {
if (!prevented) {
+ var url = element.getAttribute('href');
console.log('Click Intercept', url);
- if (typeof Frost !== 'undefined') Frost.loadUrl(url);
+ // if frost is injected, check if loading the url through an overlay works
+ if (typeof Frost !== 'undefined' && Frost.loadUrl(url)) {
+ e.stopPropagation();
+ e.preventDefault();
+ }
}
- e.stopPropagation();
- e.preventDefault();
}
}
diff --git a/app/src/main/assets/js/click_a.min.js b/app/src/main/assets/js/click_a.min.js
index c7870e2f..2033fd31 100644
--- a/app/src/main/assets/js/click_a.min.js
+++ b/app/src/main/assets/js/click_a.min.js
@@ -4,12 +4,10 @@ window.frost_click_a=!0
;var prevented=!1,_frostAClick=function(e){
var t=e.target||e.srcElement
;if("A"!==t.tagName&&(t=t.parentNode),"A"!==t.tagName&&(t=t.parentNode),
-"A"===t.tagName&&"#"!==t.getAttribute("href")){
+"A"===t.tagName&&!prevented){
var n=t.getAttribute("href")
-;if(n.includes("photoset_token"))return
-;prevented||(console.log("Click Intercept",n),
-"undefined"!=typeof Frost&&Frost.loadUrl(n)),
-e.stopPropagation(),e.preventDefault()
+;console.log("Click Intercept",n),"undefined"!=typeof Frost&&Frost.loadUrl(n)&&(e.stopPropagation(),
+e.preventDefault())
}
},_frostPreventClick=function(){
console.log("Click prevented"),prevented=!0
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt
index ad9340d7..4094a3ab 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt
@@ -54,6 +54,11 @@ fun Activity.cookies(): ArrayList<CookieModel> {
return intent?.extras?.getParcelableArrayList<CookieModel>(EXTRA_COOKIES) ?: arrayListOf()
}
+/**
+ * Launches the given url in a new overlay (if it already isn't in an overlay)
+ * Note that most requests may need to first check if the url can be launched as an overlay
+ * See [requestWebOverlay] to verify the launch
+ */
fun Context.launchWebOverlay(url: String) {
val argUrl = url.formattedFbUrl
L.v("Launch received", url)
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt
index f24a7a51..2abc9b25 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt
@@ -25,10 +25,14 @@ class FrostJSI(val webView: FrostWebViewCore) {
val cookies: ArrayList<CookieModel>
get() = activity?.cookies() ?: arrayListOf()
+ /**
+ * Attempts to load the url in an overlay
+ * Returns {@code true} if successful, meaning the event is consumed,
+ * or {@code false} otherwise, meaning the event should be propagated
+ */
@JavascriptInterface
- fun loadUrl(url: String) {
- context.launchWebOverlay(url)
- }
+ fun loadUrl(url: String?): Boolean
+ = if (url == null) false else context.requestWebOverlay(url)
@JavascriptInterface
fun reloadBaseUrl(animate: Boolean) {
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostRequestInterceptor.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostRequestInterceptor.kt
index 1a907f7f..2dfdda89 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostRequestInterceptor.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostRequestInterceptor.kt
@@ -3,6 +3,8 @@ package com.pitchedapps.frost.web
import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import android.webkit.WebView
+import ca.allanwang.kau.kotlin.LazyContext
+import ca.allanwang.kau.kotlin.lazyContext
import ca.allanwang.kau.utils.use
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.Prefs
@@ -19,41 +21,37 @@ import java.io.ByteArrayInputStream
private val blankResource: WebResourceResponse by lazy { WebResourceResponse("text/plain", "utf-8", ByteArrayInputStream("".toByteArray())) }
//these hosts will redirect to a blank resource
-private val blacklistHost: Set<String> by lazy {
- setOf(
- "edge-chat.facebook.com"
- )
-}
+private val blacklistHost: Set<String> =
+ setOf(
+ "edge-chat.facebook.com"
+ )
//these hosts will return null and skip logging
-private val whitelistHost: Set<String> by lazy {
- setOf(
- "static.xx.fbcdn.net",
- "m.facebook.com",
- "touch.facebook.com"
- )
-}
+private val whitelistHost: Set<String> =
+ setOf(
+ "static.xx.fbcdn.net",
+ "m.facebook.com",
+ "touch.facebook.com"
+ )
//these hosts will skip ad inspection
//this list does not have to include anything from the two above
-private val adWhitelistHost: Set<String> by lazy {
- setOf(
- "scontent-sea1-1.xx.fbcdn.net"
- )
-}
+private val adWhitelistHost: Set<String> =
+ setOf(
+ "scontent-sea1-1.xx.fbcdn.net"
+ )
-private var adblock: Set<String>? = null
+private val adblock: LazyContext<Set<String>> = lazyContext {
+ it.assets.open("adblock.txt").bufferedReader().use { it.readLines().toSet() }
+}
-fun shouldFrostInterceptRequest(view: WebView, request: WebResourceRequest): WebResourceResponse? {
+fun WebView.shouldFrostInterceptRequest(request: WebResourceRequest): WebResourceResponse? {
val httpUrl = HttpUrl.parse(request.url?.toString() ?: return null) ?: return null
val host = httpUrl.host()
val url = httpUrl.toString()
if (blacklistHost.contains(host)) return blankResource
if (whitelistHost.contains(host)) return null
- if (!adWhitelistHost.contains(host)) {
- if (adblock == null) adblock = view.context.assets.open("adblock.txt").bufferedReader().use { it.readLines().toSet() }
- if (adblock?.any { url.contains(it) } ?: false) return blankResource
- }
+ if (!adWhitelistHost.contains(host) && adblock(context).any { url.contains(it) }) return blankResource
if (!shouldLoadImages && !Prefs.loadMediaOnMeteredNetwork && request.isMedia) return blankResource
L.v("Intercept Request", "$host $url")
return null
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostUrlOverlayValidator.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostUrlOverlayValidator.kt
new file mode 100644
index 00000000..0a1878b3
--- /dev/null
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostUrlOverlayValidator.kt
@@ -0,0 +1,48 @@
+package com.pitchedapps.frost.web
+
+import android.content.Context
+import com.pitchedapps.frost.facebook.formattedFbUrl
+import com.pitchedapps.frost.utils.L
+import com.pitchedapps.frost.utils.isFacebookUrl
+import com.pitchedapps.frost.utils.launchWebOverlay
+
+/**
+ * Created by Allan Wang on 2017-08-15.
+ *
+ * Due to the nature of facebook href's, many links
+ * cannot be resolved on a new window and must instead
+ * by loaded in the current page
+ * This helper method will collect all known cases and launch the overlay accordingly
+ * Returns {@code true} (default) if overlay is launcher, {@code false} otherwise
+ */
+fun Context.requestWebOverlay(url: String): Boolean {
+ if (url == "#") return false
+ /*
+ * Non facebook urls can be loaded
+ */
+ if (!url.formattedFbUrl.isFacebookUrl) {
+ launchWebOverlay(url)
+ L.d("Request web overlay is not a facebook url", url)
+ return true
+ }
+ /*
+ * Check blacklist
+ */
+ if (overlayBlacklist.any { url.contains(it) }) return false
+ /*
+ * Facebook messages have the following cases for the tid query
+ * mid* or id* for newer threads, which can be launched in new windows
+ * or a hash for old threads, which must be loaded on old threads
+ */
+ if (url.contains("/messages/read/?tid=")) {
+ if (!url.contains("?tid=id") && !url.contains("?tid=mid")) return false
+ }
+ L.v("Request web overlay passed", url)
+ launchWebOverlay(url)
+ return true
+}
+
+/**
+ * The following components should never be launched in a new overlay
+ */
+val overlayBlacklist = setOf("messages/?pageNum", "photoset_token") \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt
index 2ebf2c0c..b1466ee8 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt
@@ -11,7 +11,6 @@ import com.pitchedapps.frost.activities.LoginActivity
import com.pitchedapps.frost.activities.MainActivity
import com.pitchedapps.frost.activities.SelectorActivity
import com.pitchedapps.frost.activities.WebOverlayActivity
-import com.pitchedapps.frost.facebook.FACEBOOK_COM
import com.pitchedapps.frost.facebook.FB_URL_BASE
import com.pitchedapps.frost.facebook.FbCookie
import com.pitchedapps.frost.facebook.FbItem
@@ -34,7 +33,7 @@ import org.jetbrains.anko.withAlpha
open class BaseWebViewClient : WebViewClient() {
override fun shouldInterceptRequest(view: WebView, request: WebResourceRequest): WebResourceResponse?
- = shouldFrostInterceptRequest(view, request)
+ = view.shouldFrostInterceptRequest(request)
}
@@ -125,9 +124,7 @@ open class FrostWebViewClient(val webCore: FrostWebViewCore) : BaseWebViewClient
*/
private fun launchRequest(request: WebResourceRequest): Boolean {
L.d("Launching Url", request.url?.toString() ?: "null")
- if (webCore.context is WebOverlayActivity) return false
- webCore.context.launchWebOverlay(request.url.toString())
- return true
+ return webCore.context !is WebOverlayActivity && webCore.context.requestWebOverlay(request.url.toString())
}
private fun launchImage(url: String, text: String? = null): Boolean {