aboutsummaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt4
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt16
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/facebook/FbConst.kt7
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/fragments/FragmentBase.kt2
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/injectors/JsInjector.kt48
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/services/FrostNotifications.kt7
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/services/FrostRequestService.kt7
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/services/NotificationService.kt4
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/settings/Experimental.kt7
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/settings/Notifications.kt49
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/Const.kt1
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt2
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt21
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt2
-rw-r--r--app/src/main/play/en-US/whatsnew4
-rw-r--r--app/src/main/res/values/strings_pref_experimental.xml6
-rw-r--r--app/src/main/res/xml/frost_changelog.xml4
-rw-r--r--app/src/test/kotlin/com/pitchedapps/frost/injectors/TagObfuscatorTest.kt38
-rw-r--r--app/src/web/scss/core/_core_bg.scss2
-rw-r--r--app/src/web/ts/menu.ts3
20 files changed, 199 insertions, 35 deletions
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt b/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt
index d6d6faea..2ebdd215 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt
@@ -35,7 +35,7 @@ import com.pitchedapps.frost.db.FbTabsDb
import com.pitchedapps.frost.db.FrostDatabase
import com.pitchedapps.frost.db.NotificationDb
import com.pitchedapps.frost.glide.GlideApp
-import com.pitchedapps.frost.services.scheduleNotifications
+import com.pitchedapps.frost.services.scheduleNotificationsFromPrefs
import com.pitchedapps.frost.services.setupNotificationChannels
import com.pitchedapps.frost.utils.BuildUtils
import com.pitchedapps.frost.utils.FrostPglAdBlock
@@ -96,7 +96,7 @@ class FrostApp : Application() {
setupNotificationChannels(applicationContext)
- applicationContext.scheduleNotifications(Prefs.notificationFreq)
+ scheduleNotificationsFromPrefs()
/**
* Drawer profile loading logic
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt
index 05321b69..521049e7 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt
@@ -83,6 +83,7 @@ import com.pitchedapps.frost.facebook.parsers.SearchParser
import com.pitchedapps.frost.facebook.profilePictureUrl
import com.pitchedapps.frost.fragments.BaseFragment
import com.pitchedapps.frost.fragments.WebFragment
+import com.pitchedapps.frost.services.scheduleNotificationsFromPrefs
import com.pitchedapps.frost.utils.ACTIVITY_SETTINGS
import com.pitchedapps.frost.utils.EXTRA_COOKIES
import com.pitchedapps.frost.utils.L
@@ -90,6 +91,7 @@ import com.pitchedapps.frost.utils.MAIN_TIMEOUT_DURATION
import com.pitchedapps.frost.utils.Prefs
import com.pitchedapps.frost.utils.REQUEST_FAB
import com.pitchedapps.frost.utils.REQUEST_NAV
+import com.pitchedapps.frost.utils.REQUEST_NOTIFICATION
import com.pitchedapps.frost.utils.REQUEST_REFRESH
import com.pitchedapps.frost.utils.REQUEST_RESTART
import com.pitchedapps.frost.utils.REQUEST_RESTART_APPLICATION
@@ -493,6 +495,9 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
if (hasRequest(REQUEST_FAB)) {
fragmentChannel.offer(lastPosition)
}
+ if (hasRequest(REQUEST_NOTIFICATION)) {
+ scheduleNotificationsFromPrefs()
+ }
}
}
@@ -635,12 +640,11 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
override fun getPageTitle(position: Int): CharSequence = getString(pages[position].titleId)
override fun getItemPosition(fragment: Any) =
- if (fragment !is BaseFragment)
- POSITION_UNCHANGED
- else if (fragment is WebFragment || fragment.valid)
- POSITION_UNCHANGED
- else
- POSITION_NONE
+ when {
+ fragment !is BaseFragment -> POSITION_UNCHANGED
+ fragment is WebFragment || fragment.valid -> POSITION_UNCHANGED
+ else -> POSITION_NONE
+ }
}
override val lowerVideoPadding: PointF
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbConst.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbConst.kt
index f6316470..032ff31e 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbConst.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbConst.kt
@@ -29,12 +29,15 @@ const val FB_LOGIN_URL = "${FB_URL_BASE}login"
const val FB_HOME_URL = "${FB_URL_BASE}home.php"
// Default user agent
-const val USER_AGENT_MOBILE =
+private const val USER_AGENT_MOBILE_CONST =
"Mozilla/5.0 (Linux; Android 8.0.0; ONEPLUS A3000) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36"
// Desktop agent, for pages like messages
-const val USER_AGENT_DESKTOP =
+private const val USER_AGENT_DESKTOP_CONST =
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Safari/537.36"
+const val USER_AGENT_MOBILE = USER_AGENT_DESKTOP_CONST
+const val USER_AGENT_DESKTOP = USER_AGENT_DESKTOP_CONST
+
/**
* Animation transition delay, just to ensure that the styles
* have properly set in
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/fragments/FragmentBase.kt b/app/src/main/kotlin/com/pitchedapps/frost/fragments/FragmentBase.kt
index 55fbcd40..c580c9ed 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/fragments/FragmentBase.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/fragments/FragmentBase.kt
@@ -67,7 +67,7 @@ abstract class BaseFragment : Fragment(), CoroutineScope, FragmentContract, Dyna
data: FbItem,
position: Int
): BaseFragment {
- val fragment = if (!useFallback) base() else WebFragment()
+ val fragment = if (useFallback || Prefs.webOnly) WebFragment() else base()
val d = if (data == FbItem.FEED) FeedSort(Prefs.feedSort).item else data
fragment.withArguments(
ARG_URL to d.url,
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsInjector.kt b/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsInjector.kt
index 00c7bcfc..3416c420 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsInjector.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsInjector.kt
@@ -17,9 +17,11 @@
package com.pitchedapps.frost.injectors
import android.webkit.WebView
+import androidx.annotation.VisibleForTesting
+import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.web.FrostWebViewClient
import org.apache.commons.text.StringEscapeUtils
-import java.util.Locale
+import kotlin.random.Random
class JsBuilder {
private val css = StringBuilder()
@@ -38,7 +40,7 @@ class JsBuilder {
}
fun single(tag: String): JsBuilder {
- this.tag = "_frost_${tag.toLowerCase(Locale.CANADA)}"
+ this.tag = TagObfuscator.obfuscateTag(tag)
return this
}
@@ -52,14 +54,19 @@ class JsBuilder {
val cssMin = css.replace(Regex("\\s*\n\\s*"), "")
append("var a=document.createElement('style');")
append("a.innerHTML='$cssMin';")
- if (tag != null) append("a.id='$tag';")
+ if (tag != null) {
+ append("a.id='$tag';")
+ }
append("document.head.appendChild(a);")
}
- if (js.isNotBlank())
+ if (js.isNotBlank()) {
append(js)
+ }
}
var content = builder.append("}()").toString()
- if (tag != null) content = singleInjector(tag, content)
+ if (tag != null) {
+ content = singleInjector(tag, content)
+ }
return content
}
@@ -102,3 +109,34 @@ class JsInjector(val function: String) : InjectorContract {
override fun inject(webView: WebView) =
webView.evaluateJavascript(function, null)
}
+
+/**
+ * Helper object to obfuscate window tags for JS injection.
+ */
+@VisibleForTesting
+internal object TagObfuscator {
+
+ fun obfuscateTag(tag: String): String {
+ val rnd = Random(tag.hashCode() + salt)
+ val obfuscated = buildString {
+ append(prefix)
+ append('_')
+ appendRandomChars(rnd, 16)
+ }
+ L.v { "TagObfuscator: Obfuscating tag '$tag' to '$obfuscated'" }
+ return obfuscated
+ }
+
+ private val salt: Long = System.currentTimeMillis()
+
+ private val prefix: String by lazy {
+ val rnd = Random(System.currentTimeMillis())
+ buildString { appendRandomChars(rnd, 8) }
+ }
+
+ private fun Appendable.appendRandomChars(random: Random, count: Int) {
+ for (i in 1..count) {
+ append('a' + random.nextInt(26))
+ }
+ }
+}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/services/FrostNotifications.kt b/app/src/main/kotlin/com/pitchedapps/frost/services/FrostNotifications.kt
index bb5594fe..cab1311c 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/services/FrostNotifications.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/services/FrostNotifications.kt
@@ -43,6 +43,7 @@ import com.pitchedapps.frost.facebook.parsers.NotifParser
import com.pitchedapps.frost.facebook.parsers.ParseNotification
import com.pitchedapps.frost.glide.FrostGlide
import com.pitchedapps.frost.glide.GlideApp
+import com.pitchedapps.frost.settings.hasNotifications
import com.pitchedapps.frost.utils.ARG_USER_ID
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.Prefs
@@ -321,6 +322,12 @@ data class FrostNotification(
NotificationManagerCompat.from(context).notify(tag, id, notif.build())
}
+fun Context.scheduleNotificationsFromPrefs(): Boolean {
+ val shouldSchedule = Prefs.hasNotifications
+ return if (shouldSchedule) scheduleNotifications(Prefs.notificationFreq)
+ else scheduleNotifications(-1)
+}
+
fun Context.scheduleNotifications(minutes: Long): Boolean =
scheduleJob<NotificationService>(NOTIFICATION_PERIODIC_JOB, minutes)
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/services/FrostRequestService.kt b/app/src/main/kotlin/com/pitchedapps/frost/services/FrostRequestService.kt
index 0d707dae..fe59c421 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/services/FrostRequestService.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/services/FrostRequestService.kt
@@ -31,6 +31,7 @@ import com.pitchedapps.frost.utils.EnumBundle
import com.pitchedapps.frost.utils.EnumBundleCompanion
import com.pitchedapps.frost.utils.EnumCompanion
import com.pitchedapps.frost.utils.L
+import com.pitchedapps.frost.utils.Prefs
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -162,13 +163,17 @@ class FrostRequestService : BaseJobService() {
override fun onStartJob(params: JobParameters?): Boolean {
super.onStartJob(params)
+ if (Prefs.webOnly) {
+ L.i { "Web only; skipping request service" }
+ return false
+ }
val bundle = params?.extras
if (bundle == null) {
L.eThrow("Launched ${this::class.java.simpleName} without param data")
return false
}
val cookie = bundle.getCookie()
- if (cookie.isNullOrBlank()) {
+ if (cookie.isBlank()) {
L.eThrow("Launched ${this::class.java.simpleName} without cookie")
return false
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationService.kt b/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationService.kt
index 95726974..091fbb4b 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationService.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationService.kt
@@ -72,6 +72,10 @@ class NotificationService : BaseJobService() {
override fun onStartJob(params: JobParameters?): Boolean {
super.onStartJob(params)
L.i { "Fetching notifications" }
+ if (Prefs.webOnly) {
+ L.i { "Web only mode; skipping notification service" }
+ return false
+ }
launch {
try {
sendNotifications(params)
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/settings/Experimental.kt b/app/src/main/kotlin/com/pitchedapps/frost/settings/Experimental.kt
index 7aac7526..d0963665 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/settings/Experimental.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/settings/Experimental.kt
@@ -43,6 +43,13 @@ fun SettingsActivity.getExperimentalPrefs(): KPrefAdapterBuilder.() -> Unit = {
// Experimental content starts here ------------------
+ checkbox(R.string.web_only, Prefs::webOnly, {
+ Prefs.webOnly = it
+ shouldRestartMain()
+ }) {
+ descRes = R.string.web_only_desc
+ }
+
// Experimental content ends here --------------------
checkbox(R.string.verbose_logging, Prefs::verboseLogging, {
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/settings/Notifications.kt b/app/src/main/kotlin/com/pitchedapps/frost/settings/Notifications.kt
index 4ef76b3b..ccf04935 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/settings/Notifications.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/settings/Notifications.kt
@@ -22,6 +22,7 @@ import android.media.RingtoneManager
import android.os.Build
import android.provider.Settings
import ca.allanwang.kau.kpref.activity.KPrefAdapterBuilder
+import ca.allanwang.kau.kpref.activity.KPrefItemActions
import ca.allanwang.kau.kpref.activity.items.KPrefText
import ca.allanwang.kau.utils.materialDialog
import ca.allanwang.kau.utils.minuteToText
@@ -35,8 +36,8 @@ import com.pitchedapps.frost.activities.SettingsActivity
import com.pitchedapps.frost.db.FrostDatabase
import com.pitchedapps.frost.db.deleteAll
import com.pitchedapps.frost.services.fetchNotifications
-import com.pitchedapps.frost.services.scheduleNotifications
import com.pitchedapps.frost.utils.Prefs
+import com.pitchedapps.frost.utils.REQUEST_NOTIFICATION
import com.pitchedapps.frost.utils.frostSnackbar
import com.pitchedapps.frost.utils.frostUri
import com.pitchedapps.frost.views.Keywords
@@ -45,9 +46,27 @@ import kotlinx.coroutines.launch
/**
* Created by Allan Wang on 2017-06-29.
*/
+
+val Prefs.hasNotifications: Boolean
+ get() = !webOnly && (notificationsGeneral || notificationsInstantMessages)
+
@SuppressLint("InlinedApi")
fun SettingsActivity.getNotificationPrefs(): KPrefAdapterBuilder.() -> Unit = {
+ fun KPrefItemActions.leaveWebOnlyDialog() {
+ if (Prefs.webOnly) {
+ materialDialog {
+ title(R.string.leave_web_only_title)
+ message(R.string.leave_web_only_desc)
+ positiveButton(R.string.kau_yes) {
+ Prefs.webOnly = false
+ reload()
+ }
+ negativeButton(R.string.kau_no)
+ }
+ }
+ }
+
text(
R.string.notification_frequency,
Prefs::notificationFreq,
@@ -63,16 +82,14 @@ fun SettingsActivity.getNotificationPrefs(): KPrefAdapterBuilder.() -> Unit = {
initialSelection = options.indexOf(item.pref)
) { _, index, _ ->
item.pref = options[index]
- scheduleNotifications(item.pref)
+ setFrostResult(REQUEST_NOTIFICATION)
}
}
}
- enabler = {
- val enabled = Prefs.notificationsGeneral || Prefs.notificationsInstantMessages
- if (!enabled)
- scheduleNotifications(-1)
- enabled
+ onDisabledClick = {
+ leaveWebOnlyDialog()
}
+ enabler = { Prefs.hasNotifications }
textGetter = { minuteToText(it) }
}
@@ -97,12 +114,19 @@ fun SettingsActivity.getNotificationPrefs(): KPrefAdapterBuilder.() -> Unit = {
reloadByTitle(R.string.notification_frequency)
}) {
descRes = R.string.notification_general_desc
+ enabler = { !Prefs.webOnly }
+ onDisabledClick = {
+ leaveWebOnlyDialog()
+ }
}
checkbox(R.string.notification_general_all_accounts, Prefs::notificationAllAccounts,
{ Prefs.notificationAllAccounts = it }) {
descRes = R.string.notification_general_all_accounts_desc
- enabler = Prefs::notificationsGeneral
+ enabler = { !Prefs.webOnly && Prefs.notificationsGeneral }
+ onDisabledClick = {
+ leaveWebOnlyDialog()
+ }
}
checkbox(R.string.notification_messages, Prefs::notificationsInstantMessages,
@@ -113,12 +137,19 @@ fun SettingsActivity.getNotificationPrefs(): KPrefAdapterBuilder.() -> Unit = {
reloadByTitle(R.string.notification_frequency)
}) {
descRes = R.string.notification_messages_desc
+ enabler = { !Prefs.webOnly }
+ onDisabledClick = {
+ leaveWebOnlyDialog()
+ }
}
checkbox(R.string.notification_messages_all_accounts, Prefs::notificationsImAllAccounts,
{ Prefs.notificationsImAllAccounts = it }) {
descRes = R.string.notification_messages_all_accounts_desc
- enabler = Prefs::notificationsInstantMessages
+ enabler = { !Prefs.webOnly && Prefs.notificationsInstantMessages }
+ onDisabledClick = {
+ leaveWebOnlyDialog()
+ }
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/Const.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/Const.kt
index daca9676..5f65bba1 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Const.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Const.kt
@@ -32,5 +32,6 @@ const val REQUEST_TEXT_ZOOM = 1 shl 8
const val REQUEST_NAV = 1 shl 9
const val REQUEST_SEARCH = 1 shl 10
const val REQUEST_FAB = 1 shl 11
+const val REQUEST_NOTIFICATION = 1 shl 12
const val MAIN_TIMEOUT_DURATION = 30 * 60 * 1000 // 30 min
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt
index eb8e4b35..f17645d0 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt
@@ -191,6 +191,8 @@ object Prefs : KPref() {
var showCreateFab: Boolean by kpref("show_create_fab", true)
+ var webOnly: Boolean by kpref("web_only", false)
+
inline val mainActivityLayout: MainActivityLayout
get() = MainActivityLayout(mainActivityLayoutType)
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 ecedc997..025119aa 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt
@@ -91,7 +91,7 @@ open class FrostWebViewClient(val web: FrostWebView) : BaseWebViewClient() {
override fun onPageCommitVisible(view: WebView, url: String?) {
super.onPageCommitVisible(view, url)
injectBackgroundColor()
- if (url.isFacebookUrl)
+ if (url.isFacebookUrl) {
view.jsInject(
// CssHider.CORE,
CssHider.HEADER,
@@ -111,8 +111,9 @@ open class FrostWebViewClient(val web: FrostWebView) : BaseWebViewClient() {
JsAssets.CONTEXT_A,
JsAssets.MEDIA
)
- else
+ } else {
refresh.offer(false)
+ }
}
override fun onPageFinished(view: WebView, url: String?) {
@@ -212,19 +213,27 @@ class FrostWebViewClientMenu(web: FrostWebView) : FrostWebViewClient(web) {
override fun onPageFinished(view: WebView, url: String?) {
super.onPageFinished(view, url)
- if (url == null) return
- if (url.shouldInjectMenu) jsInject(JsAssets.MENU)
+ if (url == null) {
+ return
+ }
+ if (url.shouldInjectMenu) {
+ jsInject(JsAssets.MENU)
+ }
}
override fun emit(flag: Int) {
super.emit(flag)
when (flag) {
- EMIT_FINISH -> super.injectAndFinish()
+ EMIT_FINISH -> {
+ super.injectAndFinish()
+ }
}
}
override fun onPageFinishedActions(url: String) {
v { "Should inject ${url.shouldInjectMenu}" }
- if (!url.shouldInjectMenu) injectAndFinish()
+ if (!url.shouldInjectMenu) {
+ injectAndFinish()
+ }
}
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt
index 09796b15..8e437c29 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt
@@ -33,6 +33,7 @@ import com.pitchedapps.frost.db.CookieEntity
import com.pitchedapps.frost.facebook.FB_LOGIN_URL
import com.pitchedapps.frost.facebook.FB_USER_MATCHER
import com.pitchedapps.frost.facebook.FbCookie
+import com.pitchedapps.frost.facebook.USER_AGENT_MOBILE
import com.pitchedapps.frost.facebook.get
import com.pitchedapps.frost.injectors.CssHider
import com.pitchedapps.frost.injectors.jsInject
@@ -57,6 +58,7 @@ class LoginWebView @JvmOverloads constructor(
@SuppressLint("SetJavaScriptEnabled")
private fun setupWebview() {
settings.javaScriptEnabled = true
+ settings.userAgentString = USER_AGENT_MOBILE
setLayerType(View.LAYER_TYPE_HARDWARE, null)
webViewClient = LoginClient()
webChromeClient = LoginChromeClient()
diff --git a/app/src/main/play/en-US/whatsnew b/app/src/main/play/en-US/whatsnew
index df5c33a5..80bd6988 100644
--- a/app/src/main/play/en-US/whatsnew
+++ b/app/src/main/play/en-US/whatsnew
@@ -4,4 +4,6 @@ v2.3.2
* Update theme
* Disable bugsnag completely when opting out of analytics
* Filter urls before sending to other apps
-* Allow hiding main fab (see settings > newsfeed) \ No newline at end of file
+* Allow hiding main fab (see settings > newsfeed)
+* Add some experimental options to debug login problems (settings > experimental)
+* Enforce desktop user agent for now \ No newline at end of file
diff --git a/app/src/main/res/values/strings_pref_experimental.xml b/app/src/main/res/values/strings_pref_experimental.xml
index 95d54ff2..fad29ff6 100644
--- a/app/src/main/res/values/strings_pref_experimental.xml
+++ b/app/src/main/res/values/strings_pref_experimental.xml
@@ -8,4 +8,10 @@
<string name="verbose_logging_desc">Enable verbose logging to help with crash reports. Logging will only be sent once an error is encountered, so repeat the issue to notify the dev. This will automatically be disabled if the app restarts.</string>
<string name="restart_frost">Restart Frost</string>
<string name="restart_frost_desc">Launch a cold restart for the application.</string>
+
+ <!-- Debugging phishing warnings -->
+ <string name="web_only" translatable="false">Web Only</string>
+ <string name="web_only_desc" translatable="false">Having troubles? Enable to use web exclusive features. All parsing and background services will be disabled.</string>
+ <string name="leave_web_only_title" translatable="false">Leave web only mode</string>
+ <string name="leave_web_only_desc" translatable="false">Currently in web only mode. Would you like to disable it to continue?</string>
</resources> \ No newline at end of file
diff --git a/app/src/main/res/xml/frost_changelog.xml b/app/src/main/res/xml/frost_changelog.xml
index 6e23cfb4..6142f595 100644
--- a/app/src/main/res/xml/frost_changelog.xml
+++ b/app/src/main/res/xml/frost_changelog.xml
@@ -13,7 +13,9 @@
<item text="Disable bugsnag completely when opting out of analytics" />
<item text="Filter urls before sending to other apps" />
<item text="Allow hiding main fab (see settings > newsfeed)" />
- <item text="" />
+ <item text="Add some experimental options to debug login problems (settings > experimental)" />
+ <item text="Enforce desktop user agent for now" />
+ <item text="Obfuscate js tags" />
<version title="v2.3.1" />
<item text="Hide all story panels if enabled" />
diff --git a/app/src/test/kotlin/com/pitchedapps/frost/injectors/TagObfuscatorTest.kt b/app/src/test/kotlin/com/pitchedapps/frost/injectors/TagObfuscatorTest.kt
new file mode 100644
index 00000000..e7145e39
--- /dev/null
+++ b/app/src/test/kotlin/com/pitchedapps/frost/injectors/TagObfuscatorTest.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2019 Allan Wang
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.pitchedapps.frost.injectors
+
+import java.util.UUID
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+class TagObfuscatorTest {
+
+ /**
+ * The same key should result in the same tag per session
+ */
+ @Test
+ fun consistentTags() {
+ val keys = generateSequence { UUID.randomUUID().toString() }.take(10).toSet()
+ val tags = keys.map {
+ val tag = generateSequence { TagObfuscator.obfuscateTag(it) }.take(10).toSet()
+ assertEquals(1, tag.size, "Key $it produced multiple tags: $tag")
+ tag.first()
+ }
+ assertEquals(keys.size, tags.size, "Key set and tag set have different sizes")
+ }
+}
diff --git a/app/src/web/scss/core/_core_bg.scss b/app/src/web/scss/core/_core_bg.scss
index 17c93b7b..2c76cfaf 100644
--- a/app/src/web/scss/core/_core_bg.scss
+++ b/app/src/web/scss/core/_core_bg.scss
@@ -6,7 +6,7 @@ html, body, :root, #root, #header, #MComposer, ._1upc, input, ._2f9r, ._59e9, ._
._5lp5, .container, .subpage, ._5n_f, #static_templates, ._22_8, ._1t4h, ._uoq, ._3qdh, ._8ca, ._3h8i,
._6-l ._2us7, ._6-l ._6-p:not([style*="background-image:"]), ._333v, div.sharerSelector, ._529j, ._305j, ._1pph, ._3t_l, ._4pvz,
._1g05, .acy, ._51-g, ._533c, ._ib-, .sharerAttachmentEmpty, .sharerBottomWrapper, ._24e1,
-._3bg5 ._56do, ._5hfh, ._52e-, .mQuestionsPollResultsBar, ._5hoc, ._5oxw, ._32_4, ._1hiz,
+._3bg5 ._56do, ._5hfh, ._52e-, .mQuestionsPollResultsBar, ._5hoc, ._5oxw, ._32_4, ._1hiz, ._53_-,
._38do, .bo, .cq, ._234-, ._a-5, ._2zh4, ._15ks, ._3oyc, ._36dc, ._3iyw ._3iyx, ._6bes, ._55wo, ._4-dy,
.tlBody, #timelineBody, .timelineX, .timeline, .feed, .tlPrelude, .tlFeedPlaceholder, ._4_d0,
.al, ._1gkq, ._5c5b, ._1qxg, ._5luf, ._2new, ._cld, ._3zvb, ._2nk0, .btnD, .btnI, ._2bdb, ._3ci9,
diff --git a/app/src/web/ts/menu.ts b/app/src/web/ts/menu.ts
index 6f9dbf16..b26e9cc9 100644
--- a/app/src/web/ts/menu.ts
+++ b/app/src/web/ts/menu.ts
@@ -20,6 +20,9 @@
return
}
+ /*
+ * Required to remove height restrictions
+ */
const y = new MutationObserver(() => {
viewport.removeAttribute('style');
root.removeAttribute('style');