1
0
mirror of https://github.com/AllanWang/Frost-for-Facebook.git synced 2024-11-09 20:42:34 +01:00

implement cache db and start js injections

This commit is contained in:
Allan Wang 2017-05-31 01:31:02 -07:00
parent c53e343f03
commit 9a41937a33
9 changed files with 137 additions and 122 deletions

View File

@ -1,6 +1,7 @@
package com.pitchedapps.frost
import android.app.Application
import com.pitchedapps.frost.facebook.FbCookie
import com.pitchedapps.frost.facebook.retro.FrostApi
import com.pitchedapps.frost.utils.CrashReportingTree
import com.pitchedapps.frost.utils.Prefs
@ -21,6 +22,7 @@ class FrostApp : Application() {
FlowManager.init(FlowConfig.Builder(this).build())
Prefs(this)
FrostApi(this)
FbCookie.init()
super.onCreate()
}

View File

@ -1,12 +1,14 @@
package com.pitchedapps.frost.dbflow
import com.pitchedapps.frost.facebook.FbCookie
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.Prefs
import com.raizlabs.android.dbflow.annotation.ConflictAction
import com.raizlabs.android.dbflow.annotation.Database
import com.raizlabs.android.dbflow.annotation.ForeignKey
import com.raizlabs.android.dbflow.annotation.PrimaryKey
import com.raizlabs.android.dbflow.annotation.Table
import com.raizlabs.android.dbflow.kotlinextensions.*
import com.raizlabs.android.dbflow.structure.BaseModel
import okhttp3.Cookie
import java.io.Serializable
/**
* Created by Allan Wang on 2017-05-30.
@ -18,43 +20,13 @@ object CookiesDb {
const val VERSION = 1
}
//@Database(name = CookieDb.NAME, version = CookieDb.VERSION)
//object CookieDb {
// const val NAME = "Cookie"
// const val VERSION = 1
//}
@Table(database = CookiesDb::class, allFields = true, primaryKeyConflict = ConflictAction.REPLACE)
data class CookieModel(@PrimaryKey var id: Long = Prefs.userIdDefault, var cookie: String? = null) : BaseModel()
@Table(database = CookiesDb::class, allFields = true)
data class CookieModel(@PrimaryKey var name: String,
var value: String,
var expiresAt: Long,
var domain: String,
var path: String,
var secure: Boolean,
var httpOnly: Boolean) {
fun loadFbCookie(): CookieModel? = (select from CookieModel::class where (CookieModel_Table.id eq Prefs.userId)).querySingle()
constructor(cookie: Cookie) : this(cookie.name(), cookie.value(), cookie.expiresAt(), cookie.domain(), cookie.path(), cookie.secure(), cookie.httpOnly())
constructor() : this("", "", 0L, "", "", false, false)
fun toCookie(): Cookie {
val builder = Cookie.Builder().name(name).value(value).expiresAt(expiresAt).domain(domain).path(path)
if (secure) builder.secure()
if (httpOnly) builder.httpOnly()
return builder.build()
fun saveFbCookie() {
CookieModel(FbCookie.userId, FbCookie.webCookie).async save {
L.d("Fb cookie saved")
}
fun isSecure() = secure
fun isHttpOnly() = httpOnly
}
//class CookieList(val cookies: List<Cookie>)
//class CookieDbList(val cookies: List<CookieDb>)
//@com.raizlabs.android.dbflow.annotation.TypeConverter
//class CookieTypeConverter() : TypeConverter<CookieDbList, CookieList>() {
// override fun getModelValue(data: CookieDbList): CookieList = CookieList(data.cookies.map { it.toCookie() })
// override fun getDBValue(model: CookieList): CookieDbList = CookieDbList(model.cookies.map { CookieDb(it) })
//}
@Table(database = CookiesDb::class)
data class Cookies(@PrimaryKey var url: String = "", @ForeignKey var cookie: CookieModel = CookieModel())
}

View File

@ -16,6 +16,7 @@ import com.raizlabs.android.dbflow.annotation.PrimaryKey
import com.raizlabs.android.dbflow.annotation.Table
import com.raizlabs.android.dbflow.kotlinextensions.from
import com.raizlabs.android.dbflow.sql.language.SQLite
import com.raizlabs.android.dbflow.structure.BaseModel
/**
* Created by Allan Wang on 2017-05-30.
@ -33,7 +34,7 @@ data class FbTab(val title: String, val icon: IIcon, val url: String)
data class FbTabModel(
var title: String = "",
@ForeignKey(saveForeignKeyModel = true, deleteForeignKeyModel = false) var icon: IIconModel = IIconModel(),
@PrimaryKey var url: String = "") {
@PrimaryKey var url: String = "") : BaseModel() {
constructor(fbTab: FbTab) : this(fbTab.title, IIconModel(fbTab.icon), fbTab.url)
fun toFbTab() = FbTab(title, icon.toIIcon(), url)
@ -56,15 +57,19 @@ data class IIconModel(var type: Int = -1, @PrimaryKey var name: String = "") {
}
}
enum class FbUrl(@StringRes val titleId: Int, val icon: IIcon, val url: String) {
LOGIN(R.string.feed, CommunityMaterial.Icon.cmd_newspaper, "https://www.facebook.com/v2.9/dialog/oauth?client_id=${FB_KEY}&redirect_uri=https://touch.facebook.com/&response_type=token,granted_scopes"),
FEED(R.string.feed, CommunityMaterial.Icon.cmd_newspaper, "https://touch.facebook.com/"),
PROFILE(R.string.profile, CommunityMaterial.Icon.cmd_account, "https://touch.facebook.com/me/"),
EVENTS(R.string.events, GoogleMaterial.Icon.gmd_event, "https://touch.facebook.com/events/upcoming"),
FRIENDS(R.string.friends, GoogleMaterial.Icon.gmd_people, "https://touch.facebook.com/friends/center/requests/"),
MESSAGES(R.string.messages, MaterialDesignIconic.Icon.gmi_comments, "https://touch.facebook.com/messages"),
NOTIFICATIONS(R.string.notifications, MaterialDesignIconic.Icon.gmi_globe, "https://touch.facebook.com/notifications");
const val FB_URL_BASE = "https://m.facebook.com/"
//const val FB_URL_BASE = "https://touch.facebook.com/"
enum class FbUrl(@StringRes val titleId: Int, val icon: IIcon, relativeUrl: String) {
// LOGIN(R.string.feed, CommunityMaterial.Icon.cmd_newspaper, "https://www.facebook.com/v2.9/dialog/oauth?client_id=${FB_KEY}&redirect_uri=https://touch.facebook.com/&response_type=token,granted_scopes"),
FEED(R.string.feed, CommunityMaterial.Icon.cmd_newspaper, ""),
PROFILE(R.string.profile, CommunityMaterial.Icon.cmd_account, "me"),
EVENTS(R.string.events, GoogleMaterial.Icon.gmd_event, "events/upcoming"),
FRIENDS(R.string.friends, GoogleMaterial.Icon.gmd_people, "friends/center/requests"),
MESSAGES(R.string.messages, MaterialDesignIconic.Icon.gmi_comments, "messages"),
NOTIFICATIONS(R.string.notifications, MaterialDesignIconic.Icon.gmi_globe, "notifications");
val url = "$FB_URL_BASE$relativeUrl"
fun tabInfo(c: Context) = FbTab(c.getString(titleId), icon, url)
}
@ -79,7 +84,5 @@ fun loadFbTabs(c: Context): List<FbTab> {
}
fun List<FbTab>.saveAsync(c: Context) {
map { FbTabModel(it) }.replace(c, FbTabsDb.NAME, {
L.e("Saved successfully")
})
map { FbTabModel(it) }.replace(c, FbTabsDb.NAME)
}

View File

@ -1,45 +0,0 @@
package com.pitchedapps.frost.facebook
import android.webkit.CookieManager
import com.pitchedapps.frost.utils.Prefs
/**
* Created by Allan Wang on 2017-05-30.
*/
object CookieMap {
var userId: Int = -1
private val userMatcher = "c_user=([0-9]*);"
private val map = HashMap<String, String>()
operator fun get(key: String) = map[key]
operator fun set(key: String, value: String) {
map[key] = value
}
fun put(url: String, cookie: String) {
map.put(url, cookie)
checkUserId(url, cookie)
}
fun checkUserId(url: String, cookie: String) {
if (userId != -1) return
if (!url.contains("facebook") || !cookie.contains(userMatcher)) return
val id = Regex(userMatcher).find(cookie)?.value
if (id != null) {
userId = id.toInt()
save()
}
}
fun save() {
Prefs.userId = userId
CookieManager.getInstance().flush()
}
fun reset() {
}
}

View File

@ -0,0 +1,63 @@
package com.pitchedapps.frost.facebook
import android.webkit.CookieManager
import com.pitchedapps.frost.dbflow.FB_URL_BASE
import com.pitchedapps.frost.dbflow.loadFbCookie
import com.pitchedapps.frost.dbflow.saveFbCookie
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.Prefs
/**
* Created by Allan Wang on 2017-05-30.
*/
object FbCookie {
var userId: Long = Prefs.userIdDefault
var dbCookie: String? = null
var webCookie: String?
get() = CookieManager.getInstance().getCookie(FB_URL_BASE)
set(value) = CookieManager.getInstance().setCookie(FB_URL_BASE, value)
fun init() {
userId = Prefs.userId
dbCookie = loadFbCookie()?.cookie
if (dbCookie != null && webCookie == null) {
L.d("DbCookie found & WebCookie is null; setting webcookie")
webCookie = dbCookie
}
}
private val userMatcher: Regex by lazy { Regex("c_user=([0-9]*);") }
fun checkUserId(url: String, cookie: String?) {
if (userId != Prefs.userIdDefault || cookie == null) return
L.d("Checking cookie for $url\n\t$cookie")
if (!url.contains("facebook") || !cookie.contains(userMatcher)) return
val id = userMatcher.find(cookie)?.groups?.get(1)?.value
if (id != null) {
try {
userId = id.toLong()
save()
} catch (e: NumberFormatException) {
//todo send report that id has changed
}
}
}
fun save() {
L.d("New cookie found for $userId")
Prefs.userId = userId
CookieManager.getInstance().flush()
saveFbCookie()
}
//TODO reset when new account is added; reset and clear when account is logged out
fun reset() {
Prefs.userId = Prefs.userIdDefault
userId = Prefs.userIdDefault
with(CookieManager.getInstance()) {
removeAllCookies(null)
flush()
}
}
}

View File

@ -0,0 +1,32 @@
package com.pitchedapps.frost.injectors
import android.webkit.WebView
/**
* Created by Allan Wang on 2017-05-31.
*/
class JsInjector {
private val builder = StringBuilder()
init {
builder.append("javascript:(function(){")
}
private fun getElementById(id: String) = "document.getElementById(\"$id\")"
private fun hideElementById(id: String) {
builder.append(getElementById(id)).append(".style.display=\"none\";")
}
fun hideElementById(vararg ids: String) {
ids.forEach { hideElementById(it) }
}
fun build() = builder.toString() + "})()"
fun inject(webView: WebView) {
webView.loadUrl(build())
}
override fun toString() = build()
}

View File

@ -2,8 +2,8 @@ package com.pitchedapps.frost.utils
import android.content.Context
import com.raizlabs.android.dbflow.config.FlowManager
import com.raizlabs.android.dbflow.kotlinextensions.processInTransactionAsync
import com.raizlabs.android.dbflow.kotlinextensions.save
import com.raizlabs.android.dbflow.kotlinextensions.*
import com.raizlabs.android.dbflow.structure.database.transaction.FastStoreModelTransaction
import com.raizlabs.android.dbflow.structure.database.transaction.Transaction
/**
@ -18,19 +18,8 @@ object DbUtils {
}
inline fun <reified T : Any> List<T>.replace(context: Context, dbName: String,
crossinline callback: ((successful: Boolean) -> Unit)) {
inline fun <reified T : Any> List<T>.replace(context: Context, dbName: String) {
L.d("Replacing $dbName.db")
DbUtils.db(dbName).reset(context)
this.processInTransactionAsync({
t, databaseWrapper ->
t.save(databaseWrapper)
},
Transaction.Success {
callback.invoke(true)
},
Transaction.Error { _, error ->
L.e(error.message ?: "DbReplace error")
callback.invoke(false)
})
FastStoreModelTransaction.saveBuilder(FlowManager.getModelAdapter(T::class.java)).addAll(this).build()
}

View File

@ -25,8 +25,9 @@ object Prefs {
get() = sp.getLong(LAST_ACTIVE, -1)
set(value) = set(LAST_ACTIVE, System.currentTimeMillis())
var userId: Int
get() = sp.getInt(USER_ID, -1)
const val userIdDefault = -1L
var userId: Long
get() = sp.getLong(USER_ID, userIdDefault)
set(value) = set(USER_ID, value)
private fun set(key: String, value: Boolean) = sp.edit().putBoolean(key, value).apply()

View File

@ -11,6 +11,7 @@ import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import android.webkit.*
import com.pitchedapps.frost.facebook.FbCookie
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.ObservableContainer
import io.reactivex.subjects.BehaviorSubject
@ -52,22 +53,19 @@ class FrostWebView @JvmOverloads constructor(
override fun onReceivedError(view: WebView?, request: WebResourceRequest?, error: WebResourceError?) {
super.onReceivedError(view, request, error)
observable.onNext(WebStatus.ERROR)
L.e("Error ${request}")
L.e("FWV Error ${request}")
}
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) {
super.onPageStarted(view, url, favicon)
observable.onNext(WebStatus.LOADING)
L.d("Loading $url")
L.d("FWV Loading $url")
}
override fun onPageFinished(view: WebView?, url: String?) {
override fun onPageFinished(view: WebView, url: String) {
super.onPageFinished(view, url)
observable.onNext(WebStatus.LOADED)
val cookie = CookieManager.getInstance().getCookie(url)
L.d("Loaded $url")
L.d("Cookie $cookie")
CookieManager.getInstance().flush()
FbCookie.checkUserId(url, CookieManager.getInstance().getCookie(url))
}
})
}