From bf9d5287bad0ca6b3d22437352a45b0ac9155adb Mon Sep 17 00:00:00 2001 From: Matthieu <24-artectrex@users.noreply.shinice.net> Date: Sun, 29 Nov 2020 14:58:54 +0100 Subject: [PATCH 1/5] Store refresh tokens --- .../java/com/h/pixeldroid/CameraTest.kt | 15 ++++++++------- .../java/com/h/pixeldroid/DrawerMenuTest.kt | 15 ++++++++------- .../java/com/h/pixeldroid/HomeFeedTest.kt | 15 ++++++++------- .../java/com/h/pixeldroid/IntentTest.kt | 15 ++++++++------- .../h/pixeldroid/LoginActivityOnlineTest.kt | 15 ++++++++------- .../h/pixeldroid/PostCreationFragmentTest.kt | 15 ++++++++------- .../java/com/h/pixeldroid/PostTest.kt | 15 ++++++++------- .../java/com/h/pixeldroid/LoginActivity.kt | 10 +++++----- .../main/java/com/h/pixeldroid/MainActivity.kt | 4 ++-- .../db/entities/UserDatabaseEntity.kt | 18 +++++++++--------- .../java/com/h/pixeldroid/objects/Token.kt | 1 + .../java/com/h/pixeldroid/utils/DBUtils.kt | 5 +++-- 12 files changed, 76 insertions(+), 67 deletions(-) diff --git a/app/src/androidTest/java/com/h/pixeldroid/CameraTest.kt b/app/src/androidTest/java/com/h/pixeldroid/CameraTest.kt index b3110985..8108d988 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/CameraTest.kt +++ b/app/src/androidTest/java/com/h/pixeldroid/CameraTest.kt @@ -43,13 +43,14 @@ class CameraTest { db.userDao().insertUser( UserDatabaseEntity( - user_id = "123", - instance_uri = "http://localhost", - username = "Testi", - display_name = "Testi Testo", - avatar_static = "some_avatar_url", - isActive = true, - accessToken = "token" + user_id = "123", + instance_uri = "http://localhost", + username = "Testi", + display_name = "Testi Testo", + avatar_static = "some_avatar_url", + isActive = true, + accessToken = "token", + refreshToken = refreshToken ) ) db.close() diff --git a/app/src/androidTest/java/com/h/pixeldroid/DrawerMenuTest.kt b/app/src/androidTest/java/com/h/pixeldroid/DrawerMenuTest.kt index ff42db9b..1d7950c0 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/DrawerMenuTest.kt +++ b/app/src/androidTest/java/com/h/pixeldroid/DrawerMenuTest.kt @@ -54,13 +54,14 @@ class DrawerMenuTest { db.userDao().insertUser( UserDatabaseEntity( - user_id = "123", - instance_uri = baseUrl.toString(), - username = "Testi", - display_name = "Testi Testo", - avatar_static = "some_avatar_url", - isActive = true, - accessToken = "token" + user_id = "123", + instance_uri = baseUrl.toString(), + username = "Testi", + display_name = "Testi Testo", + avatar_static = "some_avatar_url", + isActive = true, + accessToken = "token", + refreshToken = refreshToken ) ) db.close() diff --git a/app/src/androidTest/java/com/h/pixeldroid/HomeFeedTest.kt b/app/src/androidTest/java/com/h/pixeldroid/HomeFeedTest.kt index a4938384..0802a95b 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/HomeFeedTest.kt +++ b/app/src/androidTest/java/com/h/pixeldroid/HomeFeedTest.kt @@ -61,13 +61,14 @@ class HomeFeedTest { ) db.userDao().insertUser( UserDatabaseEntity( - user_id = "123", - instance_uri = baseUrl.toString(), - username = "Testi", - display_name = "Testi Testo", - avatar_static = "some_avatar_url", - isActive = true, - accessToken = "token" + user_id = "123", + instance_uri = baseUrl.toString(), + username = "Testi", + display_name = "Testi Testo", + avatar_static = "some_avatar_url", + isActive = true, + accessToken = "token", + refreshToken = refreshToken ) ) db.close() diff --git a/app/src/androidTest/java/com/h/pixeldroid/IntentTest.kt b/app/src/androidTest/java/com/h/pixeldroid/IntentTest.kt index 180c6274..1642757b 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/IntentTest.kt +++ b/app/src/androidTest/java/com/h/pixeldroid/IntentTest.kt @@ -77,13 +77,14 @@ class IntentTest { db.userDao().insertUser( UserDatabaseEntity( - user_id = "123", - instance_uri = baseUrl.toString(), - username = "Testi", - display_name = "Testi Testo", - avatar_static = "some_avatar_url", - isActive = true, - accessToken = "token" + user_id = "123", + instance_uri = baseUrl.toString(), + username = "Testi", + display_name = "Testi Testo", + avatar_static = "some_avatar_url", + isActive = true, + accessToken = "token", + refreshToken = refreshToken ) ) db.close() diff --git a/app/src/androidTest/java/com/h/pixeldroid/LoginActivityOnlineTest.kt b/app/src/androidTest/java/com/h/pixeldroid/LoginActivityOnlineTest.kt index 5354544b..2c33cdfb 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/LoginActivityOnlineTest.kt +++ b/app/src/androidTest/java/com/h/pixeldroid/LoginActivityOnlineTest.kt @@ -117,13 +117,14 @@ class LoginActivityOnlineTest { db.userDao().insertUser( UserDatabaseEntity( - user_id = "123", - instance_uri = server.getUrl().toString(), - username = "Testi", - display_name = "Testi Testo", - avatar_static = "some_avatar_url", - isActive = true, - accessToken = "token" + user_id = "123", + instance_uri = server.getUrl().toString(), + username = "Testi", + display_name = "Testi Testo", + avatar_static = "some_avatar_url", + isActive = true, + accessToken = "token", + refreshToken = refreshToken ) ) db.close() diff --git a/app/src/androidTest/java/com/h/pixeldroid/PostCreationFragmentTest.kt b/app/src/androidTest/java/com/h/pixeldroid/PostCreationFragmentTest.kt index f1e69c6a..0ea5de6d 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/PostCreationFragmentTest.kt +++ b/app/src/androidTest/java/com/h/pixeldroid/PostCreationFragmentTest.kt @@ -89,13 +89,14 @@ class PostFragmentUITests { db.userDao().insertUser( UserDatabaseEntity( - user_id = "123", - instance_uri = baseUrl.toString(), - username = "Testi", - display_name = "Testi Testo", - avatar_static = "some_avatar_url", - isActive = true, - accessToken = "token" + user_id = "123", + instance_uri = baseUrl.toString(), + username = "Testi", + display_name = "Testi Testo", + avatar_static = "some_avatar_url", + isActive = true, + accessToken = "token", + refreshToken = refreshToken ) ) db.close() diff --git a/app/src/androidTest/java/com/h/pixeldroid/PostTest.kt b/app/src/androidTest/java/com/h/pixeldroid/PostTest.kt index 25e6fef3..e2b8f7ea 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/PostTest.kt +++ b/app/src/androidTest/java/com/h/pixeldroid/PostTest.kt @@ -55,13 +55,14 @@ class PostTest { db.userDao().insertUser( UserDatabaseEntity( - user_id = "123", - instance_uri = baseUrl.toString(), - username = "Testi", - display_name = "Testi Testo", - avatar_static = "some_avatar_url", - isActive = true, - accessToken = "token" + user_id = "123", + instance_uri = baseUrl.toString(), + username = "Testi", + display_name = "Testi Testo", + avatar_static = "some_avatar_url", + isActive = true, + accessToken = "token", + refreshToken = refreshToken ) ) db.close() diff --git a/app/src/main/java/com/h/pixeldroid/LoginActivity.kt b/app/src/main/java/com/h/pixeldroid/LoginActivity.kt index db714126..1b7bd317 100644 --- a/app/src/main/java/com/h/pixeldroid/LoginActivity.kt +++ b/app/src/main/java/com/h/pixeldroid/LoginActivity.kt @@ -24,7 +24,6 @@ import io.reactivex.SingleObserver import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable import io.reactivex.functions.BiFunction -import io.reactivex.functions.Function3 import io.reactivex.schedulers.Schedulers import kotlinx.android.synthetic.main.activity_login.* import okhttp3.HttpUrl @@ -256,7 +255,7 @@ class LoginActivity : AppCompatActivity() { //TODO check why we can't do onErrorReturn { null } which would make more sense ¯\_(ツ)_/¯ //Also, maybe find a nicer way to do this, this feels hacky (although it can work fine) val nullInstance = Instance(null, null, null, null, null, null, null, null) - val nullToken = Token(null, null, null, null) + val nullToken = Token(null, null, null, null, null) Single.zip( pixelfedAPI.instance().onErrorReturn { nullInstance }, @@ -280,7 +279,7 @@ class LoginActivity : AppCompatActivity() { } DBUtils.storeInstance(db, instance) - storeUser(token.access_token, instance.uri) + storeUser(token.access_token, token.refresh_token, instance.uri) wipeSharedSettings() } @@ -314,7 +313,7 @@ class LoginActivity : AppCompatActivity() { } } - private fun storeUser(accessToken: String, instance: String) { + private fun storeUser(accessToken: String, refreshToken: String?, instance: String) { pixelfedAPI.verifyCredentials("Bearer $accessToken") .enqueue(object : Callback { override fun onResponse(call: Call, response: Response) { @@ -326,7 +325,8 @@ class LoginActivity : AppCompatActivity() { user, instance, activeUser = true, - accessToken = accessToken + accessToken = accessToken, + refreshToken = refreshToken ) apiHolder.setDomainToCurrentUser(db) val intent = Intent(this@LoginActivity, MainActivity::class.java) diff --git a/app/src/main/java/com/h/pixeldroid/MainActivity.kt b/app/src/main/java/com/h/pixeldroid/MainActivity.kt index 1f42571f..a627a09e 100644 --- a/app/src/main/java/com/h/pixeldroid/MainActivity.kt +++ b/app/src/main/java/com/h/pixeldroid/MainActivity.kt @@ -8,7 +8,6 @@ import android.os.Bundle import android.util.Log import android.view.View import android.widget.ImageView -import androidx.annotation.DrawableRes import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat import androidx.core.view.GravityCompat @@ -190,6 +189,7 @@ class MainActivity : AppCompatActivity() { if (hasInternet(applicationContext)) { val domain = user?.instance_uri.orEmpty() val accessToken = user?.accessToken.orEmpty() + val refreshToken = user?.refreshToken val api = apiHolder.api ?: apiHolder.setDomainToCurrentUser(db) api.verifyCredentials("Bearer $accessToken") .enqueue(object : Callback { @@ -199,7 +199,7 @@ class MainActivity : AppCompatActivity() { ) { if (response.body() != null && response.isSuccessful) { val account = response.body() as Account - DBUtils.addUser(db, account, domain, accessToken = accessToken) + DBUtils.addUser(db, account, domain, accessToken = accessToken, refreshToken = refreshToken) fillDrawerAccountInfo(account.id!!) } } diff --git a/app/src/main/java/com/h/pixeldroid/db/entities/UserDatabaseEntity.kt b/app/src/main/java/com/h/pixeldroid/db/entities/UserDatabaseEntity.kt index 8e1653f7..0b258414 100644 --- a/app/src/main/java/com/h/pixeldroid/db/entities/UserDatabaseEntity.kt +++ b/app/src/main/java/com/h/pixeldroid/db/entities/UserDatabaseEntity.kt @@ -3,7 +3,6 @@ package com.h.pixeldroid.db.entities import androidx.room.Entity import androidx.room.ForeignKey import androidx.room.Index -import com.h.pixeldroid.db.entities.InstanceDatabaseEntity @Entity( tableName = "users", @@ -17,12 +16,13 @@ import com.h.pixeldroid.db.entities.InstanceDatabaseEntity )], indices = [Index(value = ["instance_uri"])] ) -data class UserDatabaseEntity ( - var user_id: String, - var instance_uri: String, - var username: String, - var display_name: String, - var avatar_static: String, - var isActive: Boolean, - var accessToken: String +data class UserDatabaseEntity( + var user_id: String, + var instance_uri: String, + var username: String, + var display_name: String, + var avatar_static: String, + var isActive: Boolean, + var accessToken: String, + val refreshToken: String? ) \ No newline at end of file diff --git a/app/src/main/java/com/h/pixeldroid/objects/Token.kt b/app/src/main/java/com/h/pixeldroid/objects/Token.kt index e22e170d..8f08e538 100644 --- a/app/src/main/java/com/h/pixeldroid/objects/Token.kt +++ b/app/src/main/java/com/h/pixeldroid/objects/Token.kt @@ -2,6 +2,7 @@ package com.h.pixeldroid.objects data class Token( val access_token: String?, + val refresh_token: String?, val token_type: String?, val scope: String?, val created_at: Int? diff --git a/app/src/main/java/com/h/pixeldroid/utils/DBUtils.kt b/app/src/main/java/com/h/pixeldroid/utils/DBUtils.kt index 14b261e5..090ef283 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/DBUtils.kt +++ b/app/src/main/java/com/h/pixeldroid/utils/DBUtils.kt @@ -19,7 +19,7 @@ class DBUtils { } } - fun addUser(db: AppDatabase, account: Account, instance_uri: String, activeUser: Boolean = true, accessToken: String) { + fun addUser(db: AppDatabase, account: Account, instance_uri: String, activeUser: Boolean = true, accessToken: String, refreshToken: String?) { db.userDao().insertUser( UserDatabaseEntity( user_id = account.id!!, @@ -29,7 +29,8 @@ class DBUtils { display_name = account.getDisplayName(), avatar_static = account.avatar_static.orEmpty(), isActive = activeUser, - accessToken = accessToken + accessToken = accessToken, + refreshToken = refreshToken ) ) } From 3370001c4cb062d19f5fdd18fdeb3242ea0be7bd Mon Sep 17 00:00:00 2001 From: Matthieu <24-artectrex@users.noreply.shinice.net> Date: Sun, 29 Nov 2020 20:19:25 +0100 Subject: [PATCH 2/5] store client ID and secret, and set up refresh if a request fails with 401 --- .../java/com/h/pixeldroid/CameraTest.kt | 4 +- .../java/com/h/pixeldroid/DrawerMenuTest.kt | 4 +- .../java/com/h/pixeldroid/HomeFeedTest.kt | 4 +- .../java/com/h/pixeldroid/IntentTest.kt | 4 +- .../h/pixeldroid/LoginActivityOnlineTest.kt | 4 +- .../h/pixeldroid/PostCreationFragmentTest.kt | 4 +- .../java/com/h/pixeldroid/PostTest.kt | 4 +- .../java/com/h/pixeldroid/LoginActivity.kt | 15 ++++--- .../java/com/h/pixeldroid/MainActivity.kt | 4 +- .../java/com/h/pixeldroid/api/PixelfedAPI.kt | 13 +++--- .../db/entities/UserDatabaseEntity.kt | 4 +- .../java/com/h/pixeldroid/di/APIModule.kt | 44 +++++++++++++++---- .../h/pixeldroid/fragments/PostFragment.kt | 2 +- .../cachedFeeds/postFeeds/PostFeedFragment.kt | 4 +- .../search/SearchPostsFragment.kt | 4 +- .../java/com/h/pixeldroid/utils/DBUtils.kt | 27 +++++++----- .../test/java/com/h/pixeldroid/APIUnitTest.kt | 12 ++--- 17 files changed, 102 insertions(+), 55 deletions(-) diff --git a/app/src/androidTest/java/com/h/pixeldroid/CameraTest.kt b/app/src/androidTest/java/com/h/pixeldroid/CameraTest.kt index 8108d988..c2e53180 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/CameraTest.kt +++ b/app/src/androidTest/java/com/h/pixeldroid/CameraTest.kt @@ -50,7 +50,9 @@ class CameraTest { avatar_static = "some_avatar_url", isActive = true, accessToken = "token", - refreshToken = refreshToken + refreshToken = refreshToken, + clientId = clientId, + clientSecret = clientSecret ) ) db.close() diff --git a/app/src/androidTest/java/com/h/pixeldroid/DrawerMenuTest.kt b/app/src/androidTest/java/com/h/pixeldroid/DrawerMenuTest.kt index 1d7950c0..150b590a 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/DrawerMenuTest.kt +++ b/app/src/androidTest/java/com/h/pixeldroid/DrawerMenuTest.kt @@ -61,7 +61,9 @@ class DrawerMenuTest { avatar_static = "some_avatar_url", isActive = true, accessToken = "token", - refreshToken = refreshToken + refreshToken = refreshToken, + clientId = clientId, + clientSecret = clientSecret ) ) db.close() diff --git a/app/src/androidTest/java/com/h/pixeldroid/HomeFeedTest.kt b/app/src/androidTest/java/com/h/pixeldroid/HomeFeedTest.kt index 0802a95b..c4b49076 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/HomeFeedTest.kt +++ b/app/src/androidTest/java/com/h/pixeldroid/HomeFeedTest.kt @@ -68,7 +68,9 @@ class HomeFeedTest { avatar_static = "some_avatar_url", isActive = true, accessToken = "token", - refreshToken = refreshToken + refreshToken = refreshToken, + clientId = clientId, + clientSecret = clientSecret ) ) db.close() diff --git a/app/src/androidTest/java/com/h/pixeldroid/IntentTest.kt b/app/src/androidTest/java/com/h/pixeldroid/IntentTest.kt index 1642757b..87fe9641 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/IntentTest.kt +++ b/app/src/androidTest/java/com/h/pixeldroid/IntentTest.kt @@ -84,7 +84,9 @@ class IntentTest { avatar_static = "some_avatar_url", isActive = true, accessToken = "token", - refreshToken = refreshToken + refreshToken = refreshToken, + clientId = clientId, + clientSecret = clientSecret ) ) db.close() diff --git a/app/src/androidTest/java/com/h/pixeldroid/LoginActivityOnlineTest.kt b/app/src/androidTest/java/com/h/pixeldroid/LoginActivityOnlineTest.kt index 2c33cdfb..bafffc8a 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/LoginActivityOnlineTest.kt +++ b/app/src/androidTest/java/com/h/pixeldroid/LoginActivityOnlineTest.kt @@ -124,7 +124,9 @@ class LoginActivityOnlineTest { avatar_static = "some_avatar_url", isActive = true, accessToken = "token", - refreshToken = refreshToken + refreshToken = refreshToken, + clientId = clientId, + clientSecret = clientSecret ) ) db.close() diff --git a/app/src/androidTest/java/com/h/pixeldroid/PostCreationFragmentTest.kt b/app/src/androidTest/java/com/h/pixeldroid/PostCreationFragmentTest.kt index 0ea5de6d..82e73224 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/PostCreationFragmentTest.kt +++ b/app/src/androidTest/java/com/h/pixeldroid/PostCreationFragmentTest.kt @@ -96,7 +96,9 @@ class PostFragmentUITests { avatar_static = "some_avatar_url", isActive = true, accessToken = "token", - refreshToken = refreshToken + refreshToken = refreshToken, + clientId = clientId, + clientSecret = clientSecret ) ) db.close() diff --git a/app/src/androidTest/java/com/h/pixeldroid/PostTest.kt b/app/src/androidTest/java/com/h/pixeldroid/PostTest.kt index e2b8f7ea..8289fc7c 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/PostTest.kt +++ b/app/src/androidTest/java/com/h/pixeldroid/PostTest.kt @@ -62,7 +62,9 @@ class PostTest { avatar_static = "some_avatar_url", isActive = true, accessToken = "token", - refreshToken = refreshToken + refreshToken = refreshToken, + clientId = clientId, + clientSecret = clientSecret ) ) db.close() diff --git a/app/src/main/java/com/h/pixeldroid/LoginActivity.kt b/app/src/main/java/com/h/pixeldroid/LoginActivity.kt index 1b7bd317..1214df8b 100644 --- a/app/src/main/java/com/h/pixeldroid/LoginActivity.kt +++ b/app/src/main/java/com/h/pixeldroid/LoginActivity.kt @@ -30,6 +30,9 @@ import okhttp3.HttpUrl import retrofit2.Call import retrofit2.Callback import retrofit2.Response +import retrofit2.Retrofit +import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory +import retrofit2.converter.gson.GsonConverterFactory import javax.inject.Inject /** Overview of the flow of the login process: (boxes are requests done in parallel, @@ -137,7 +140,7 @@ class LoginActivity : AppCompatActivity() { hideKeyboard() loadingAnimation(true) - pixelfedAPI = apiHolder.setDomain(normalizedDomain) + pixelfedAPI = PixelfedAPI.createFromUrl(normalizedDomain) Single.zip( pixelfedAPI.registerApplication( @@ -250,7 +253,7 @@ class LoginActivity : AppCompatActivity() { } //Successful authorization - pixelfedAPI = apiHolder.setDomain(domain) + pixelfedAPI = PixelfedAPI.createFromUrl(domain) //TODO check why we can't do onErrorReturn { null } which would make more sense ¯\_(ツ)_/¯ //Also, maybe find a nicer way to do this, this feels hacky (although it can work fine) @@ -279,7 +282,7 @@ class LoginActivity : AppCompatActivity() { } DBUtils.storeInstance(db, instance) - storeUser(token.access_token, token.refresh_token, instance.uri) + storeUser(token.access_token, token.refresh_token, clientId, clientSecret, instance.uri) wipeSharedSettings() } @@ -313,7 +316,7 @@ class LoginActivity : AppCompatActivity() { } } - private fun storeUser(accessToken: String, refreshToken: String?, instance: String) { + private fun storeUser(accessToken: String, refreshToken: String?, clientId: String, clientSecret: String, instance: String) { pixelfedAPI.verifyCredentials("Bearer $accessToken") .enqueue(object : Callback { override fun onResponse(call: Call, response: Response) { @@ -326,7 +329,9 @@ class LoginActivity : AppCompatActivity() { instance, activeUser = true, accessToken = accessToken, - refreshToken = refreshToken + refreshToken = refreshToken, + clientId = clientId, + clientSecret = clientSecret ) apiHolder.setDomainToCurrentUser(db) val intent = Intent(this@LoginActivity, MainActivity::class.java) diff --git a/app/src/main/java/com/h/pixeldroid/MainActivity.kt b/app/src/main/java/com/h/pixeldroid/MainActivity.kt index a627a09e..e3bf9695 100644 --- a/app/src/main/java/com/h/pixeldroid/MainActivity.kt +++ b/app/src/main/java/com/h/pixeldroid/MainActivity.kt @@ -190,6 +190,8 @@ class MainActivity : AppCompatActivity() { val domain = user?.instance_uri.orEmpty() val accessToken = user?.accessToken.orEmpty() val refreshToken = user?.refreshToken + val clientId = user?.clientId.orEmpty() + val clientSecret = user?.clientSecret.orEmpty() val api = apiHolder.api ?: apiHolder.setDomainToCurrentUser(db) api.verifyCredentials("Bearer $accessToken") .enqueue(object : Callback { @@ -199,7 +201,7 @@ class MainActivity : AppCompatActivity() { ) { if (response.body() != null && response.isSuccessful) { val account = response.body() as Account - DBUtils.addUser(db, account, domain, accessToken = accessToken, refreshToken = refreshToken) + DBUtils.addUser(db, account, domain, accessToken = accessToken, refreshToken = refreshToken, clientId = clientId, clientSecret = clientSecret) fillDrawerAccountInfo(account.id!!) } } diff --git a/app/src/main/java/com/h/pixeldroid/api/PixelfedAPI.kt b/app/src/main/java/com/h/pixeldroid/api/PixelfedAPI.kt index d9c51723..79fa7711 100644 --- a/app/src/main/java/com/h/pixeldroid/api/PixelfedAPI.kt +++ b/app/src/main/java/com/h/pixeldroid/api/PixelfedAPI.kt @@ -23,11 +23,7 @@ interface PixelfedAPI { companion object { - @Deprecated( - "Use the DI-d PixelfedAPIHolder instead", - ReplaceWith("apiHolder.api") - ) - fun create(baseUrl: String): PixelfedAPI { + fun createFromUrl(baseUrl: String): PixelfedAPI { return Retrofit.Builder() .baseUrl(baseUrl) .addConverterFactory(GsonConverterFactory.create()) @@ -52,11 +48,12 @@ interface PixelfedAPI { fun obtainToken( @Field("client_id") client_id: String, @Field("client_secret") client_secret: String, - @Field("redirect_uri") redirect_uri: String, + @Field("redirect_uri") redirect_uri: String? = null, @Field("scope") scope: String? = "read", @Field("code") code: String? = null, - @Field("grant_type") grant_type: String? = null - ): Single + @Field("grant_type") grant_type: String? = null, + @Field("refresh_token") refresh_token: String? = null + ): Single // get instance configuration @GET("/api/v1/instance") diff --git a/app/src/main/java/com/h/pixeldroid/db/entities/UserDatabaseEntity.kt b/app/src/main/java/com/h/pixeldroid/db/entities/UserDatabaseEntity.kt index 0b258414..fee41068 100644 --- a/app/src/main/java/com/h/pixeldroid/db/entities/UserDatabaseEntity.kt +++ b/app/src/main/java/com/h/pixeldroid/db/entities/UserDatabaseEntity.kt @@ -24,5 +24,7 @@ data class UserDatabaseEntity( var avatar_static: String, var isActive: Boolean, var accessToken: String, - val refreshToken: String? + val refreshToken: String?, + val clientId: String, + val clientSecret: String ) \ No newline at end of file diff --git a/app/src/main/java/com/h/pixeldroid/di/APIModule.kt b/app/src/main/java/com/h/pixeldroid/di/APIModule.kt index 462cbf1e..96cb0520 100644 --- a/app/src/main/java/com/h/pixeldroid/di/APIModule.kt +++ b/app/src/main/java/com/h/pixeldroid/di/APIModule.kt @@ -2,11 +2,14 @@ package com.h.pixeldroid.di import com.h.pixeldroid.api.PixelfedAPI import com.h.pixeldroid.db.AppDatabase +import com.h.pixeldroid.db.entities.UserDatabaseEntity import dagger.Module import dagger.Provides +import okhttp3.* import retrofit2.Retrofit import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory import retrofit2.converter.gson.GsonConverterFactory +import java.lang.Exception import javax.inject.Singleton @Module @@ -15,26 +18,51 @@ class APIModule{ @Provides @Singleton fun providesAPIHolder(db: AppDatabase): PixelfedAPIHolder { - return PixelfedAPIHolder(db.userDao().getActiveUser()?.instance_uri) + return PixelfedAPIHolder(db.userDao().getActiveUser()) } - } +class TokenAuthenticator(val user: UserDatabaseEntity) : Authenticator { -class PixelfedAPIHolder(domain: String?){ + val pixelfedAPI = PixelfedAPI.createFromUrl(user.instance_uri) + + override fun authenticate(route: Route?, response: Response): Request? { + + if (response.request.header("Authorization") != null) { + return null // Give up, we've already failed to authenticate. + } + // Refresh the access_token using a synchronous api request + val newAccessToken: String = try { + pixelfedAPI.obtainToken( + scope = "", grant_type = "refresh_token", + refresh_token = user.refreshToken, client_id = user.clientId, client_secret = user.clientSecret + ).blockingGet().access_token + }catch (e: Exception){ + null + }.orEmpty() + + // Add new header to rejected request and retry it + return response.request.newBuilder() + .header("Authorization", "Bearer $newAccessToken") + .build() + } +} + +class PixelfedAPIHolder(user: UserDatabaseEntity?){ private val intermediate: Retrofit.Builder = Retrofit.Builder() .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) - var api: PixelfedAPI? = if (domain != null) setDomain(domain) else null + var api: PixelfedAPI? = if (user != null) setDomain(user) else null fun setDomainToCurrentUser(db: AppDatabase): PixelfedAPI { - return setDomain(db.userDao().getActiveUser()!!.instance_uri) + return setDomain(db.userDao().getActiveUser()!!) } - fun setDomain(domain: String): PixelfedAPI { + fun setDomain(user: UserDatabaseEntity): PixelfedAPI { val newAPI = intermediate - .baseUrl(domain) - .build().create(PixelfedAPI::class.java) + .baseUrl(user.instance_uri) + .client(OkHttpClient().newBuilder().authenticator(TokenAuthenticator(user)).build()) + .build().create(PixelfedAPI::class.java) api = newAPI return newAPI } diff --git a/app/src/main/java/com/h/pixeldroid/fragments/PostFragment.kt b/app/src/main/java/com/h/pixeldroid/fragments/PostFragment.kt index dd72a5ed..c3adfe9b 100644 --- a/app/src/main/java/com/h/pixeldroid/fragments/PostFragment.kt +++ b/app/src/main/java/com/h/pixeldroid/fragments/PostFragment.kt @@ -32,7 +32,7 @@ class PostFragment : BaseFragment() { val user = db.userDao().getActiveUser()!! - val api = apiHolder.api ?: apiHolder.setDomain(user.instance_uri) + val api = apiHolder.api ?: apiHolder.setDomain(user) val holder = StatusViewHolder(root) diff --git a/app/src/main/java/com/h/pixeldroid/fragments/feeds/cachedFeeds/postFeeds/PostFeedFragment.kt b/app/src/main/java/com/h/pixeldroid/fragments/feeds/cachedFeeds/postFeeds/PostFeedFragment.kt index 9748e81b..9cc4176d 100644 --- a/app/src/main/java/com/h/pixeldroid/fragments/feeds/cachedFeeds/postFeeds/PostFeedFragment.kt +++ b/app/src/main/java/com/h/pixeldroid/fragments/feeds/cachedFeeds/postFeeds/PostFeedFragment.kt @@ -89,8 +89,8 @@ class PostFeedFragment: CachedFeedFragment() { override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { val uiModel = getItem(position) as Status uiModel.let { - val instanceUri = db.userDao().getActiveUser()!!.instance_uri - (holder as StatusViewHolder).bind(it, apiHolder.setDomain(instanceUri), db, lifecycleScope) + val user = db.userDao().getActiveUser()!! + (holder as StatusViewHolder).bind(it, apiHolder.setDomain(user), db, lifecycleScope) } } } diff --git a/app/src/main/java/com/h/pixeldroid/fragments/feeds/uncachedFeeds/search/SearchPostsFragment.kt b/app/src/main/java/com/h/pixeldroid/fragments/feeds/uncachedFeeds/search/SearchPostsFragment.kt index 007af135..a7fbf6aa 100644 --- a/app/src/main/java/com/h/pixeldroid/fragments/feeds/uncachedFeeds/search/SearchPostsFragment.kt +++ b/app/src/main/java/com/h/pixeldroid/fragments/feeds/uncachedFeeds/search/SearchPostsFragment.kt @@ -79,8 +79,8 @@ class SearchPostsFragment : UncachedFeedFragment() { override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { val uiModel = getItem(position) as Status uiModel.let { - val instanceUri = db.userDao().getActiveUser()!!.instance_uri - (holder as StatusViewHolder).bind(it, apiHolder.setDomain(instanceUri), db, lifecycleScope) + val user = db.userDao().getActiveUser()!! + (holder as StatusViewHolder).bind(it, apiHolder.setDomain(user), db, lifecycleScope) } } } diff --git a/app/src/main/java/com/h/pixeldroid/utils/DBUtils.kt b/app/src/main/java/com/h/pixeldroid/utils/DBUtils.kt index 090ef283..83e62c07 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/DBUtils.kt +++ b/app/src/main/java/com/h/pixeldroid/utils/DBUtils.kt @@ -19,20 +19,23 @@ class DBUtils { } } - fun addUser(db: AppDatabase, account: Account, instance_uri: String, activeUser: Boolean = true, accessToken: String, refreshToken: String?) { + fun addUser(db: AppDatabase, account: Account, instance_uri: String, activeUser: Boolean = true, + accessToken: String, refreshToken: String?, clientId: String, clientSecret: String) { db.userDao().insertUser( UserDatabaseEntity( - user_id = account.id!!, - //make sure not to normalize to https when localhost, to allow testing - instance_uri = normalizeOrNot(instance_uri), - username = account.username!!, - display_name = account.getDisplayName(), - avatar_static = account.avatar_static.orEmpty(), - isActive = activeUser, - accessToken = accessToken, - refreshToken = refreshToken - ) - ) + user_id = account.id!!, + //make sure not to normalize to https when localhost, to allow testing + instance_uri = normalizeOrNot(instance_uri), + username = account.username!!, + display_name = account.getDisplayName(), + avatar_static = account.avatar_static.orEmpty(), + isActive = activeUser, + accessToken = accessToken, + refreshToken = refreshToken, + clientId = clientId, + clientSecret = clientSecret + ) + ) } fun storeInstance(db: AppDatabase, instance: Instance) { diff --git a/app/src/test/java/com/h/pixeldroid/APIUnitTest.kt b/app/src/test/java/com/h/pixeldroid/APIUnitTest.kt index 06a0f4d9..7581823c 100644 --- a/app/src/test/java/com/h/pixeldroid/APIUnitTest.kt +++ b/app/src/test/java/com/h/pixeldroid/APIUnitTest.kt @@ -5,15 +5,11 @@ import com.github.tomakehurst.wiremock.junit.WireMockRule import com.h.pixeldroid.api.PixelfedAPI import com.h.pixeldroid.objects.* import io.reactivex.Single -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import org.junit.Assert.assertEquals import org.junit.Rule import org.junit.Test -import retrofit2.Call import java.text.SimpleDateFormat -import java.util.* /** @@ -92,9 +88,9 @@ class APIUnitTest { val statusesHome: List runBlocking { - statuses = PixelfedAPI.create("http://localhost:8089") + statuses = PixelfedAPI.createFromUrl("http://localhost:8089") .timelinePublic(null, null, null, null, null) - statusesHome = PixelfedAPI.create("http://localhost:8089") + statusesHome = PixelfedAPI.createFromUrl("http://localhost:8089") .timelineHome("abc", null, null, null,null, null) } @@ -116,7 +112,7 @@ class APIUnitTest { .withHeader("Content-Type", "application/json") .withBody(""" {"id":3197,"name":"Pixeldroid","website":null,"redirect_uri":"urn:ietf:wg:oauth:2.0:oob","client_id":3197,"client_secret":"hhRwLupqUJPghKsZzpZtxNV67g5DBdPYCqW6XE3m","vapid_key":null}""" ))) - val call: Single = PixelfedAPI.create("http://localhost:8089") + val call: Single = PixelfedAPI.createFromUrl("http://localhost:8089") .registerApplication("Pixeldroid", "urn:ietf:wg:oauth:2.0:oob", "read write follow") val application: Application = call.toFuture().get() @@ -144,7 +140,7 @@ class APIUnitTest { val OAUTH_SCHEME = "oauth2redirect" val SCOPE = "read write follow" val PACKAGE_ID = "com.h.pixeldroid" - val call: Single = PixelfedAPI.create("http://localhost:8089") + val call: Single = PixelfedAPI.createFromUrl("http://localhost:8089") .obtainToken("123", "ssqdfqsdfqds", "$OAUTH_SCHEME://$PACKAGE_ID", SCOPE, "abc", "authorization_code") val token: Token = call.toFuture().get() From e3f9539af2d5322224cf2a9c038f5b83392a6c58 Mon Sep 17 00:00:00 2001 From: Matthieu <24-artectrex@users.noreply.shinice.net> Date: Sun, 29 Nov 2020 20:35:26 +0100 Subject: [PATCH 3/5] Fix unit test for token --- app/src/test/java/com/h/pixeldroid/APIUnitTest.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/test/java/com/h/pixeldroid/APIUnitTest.kt b/app/src/test/java/com/h/pixeldroid/APIUnitTest.kt index 7581823c..7806252f 100644 --- a/app/src/test/java/com/h/pixeldroid/APIUnitTest.kt +++ b/app/src/test/java/com/h/pixeldroid/APIUnitTest.kt @@ -132,6 +132,7 @@ class APIUnitTest { .withHeader("Content-Type", "application/json") .withBody("""{ "access_token": "ZA-Yj3aBD8U8Cm7lKUp-lm9O9BmDgdhHzDeqsY8tlL0", + "refresh_token": "ZA-Yj3aBD8U8Cm7lKUp-sqfdsqfdqfsdfqds", "token_type": "Bearer", "scope": "read write follow push", "created_at": 1573979017 @@ -148,7 +149,7 @@ class APIUnitTest { assertEquals("Bearer", token.token_type) assertEquals("read write follow push", token.scope) assertEquals(1573979017, token.created_at) - assertEquals(Token("ZA-Yj3aBD8U8Cm7lKUp-lm9O9BmDgdhHzDeqsY8tlL0", "Bearer", "read write follow push",1573979017), token) + assertEquals(Token("ZA-Yj3aBD8U8Cm7lKUp-lm9O9BmDgdhHzDeqsY8tlL0", "ZA-Yj3aBD8U8Cm7lKUp-sqfdsqfdqfsdfqds","Bearer", "read write follow push",1573979017), token) } From 570b76ecdc0f1173ea2e340241350a6ad2941676 Mon Sep 17 00:00:00 2001 From: Matthieu <24-artectrex@users.noreply.shinice.net> Date: Tue, 8 Dec 2020 18:12:00 +0100 Subject: [PATCH 4/5] update dependencies --- app/build.gradle | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index ccce5c97..5088fefa 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -72,14 +72,14 @@ dependencies { implementation 'androidx.core:core-ktx:1.3.2' implementation 'androidx.preference:preference-ktx:1.1.1' implementation 'androidx.constraintlayout:constraintlayout:2.0.4' - implementation 'androidx.navigation:navigation-fragment-ktx:2.3.1' - implementation 'androidx.navigation:navigation-ui-ktx:2.3.1' - implementation "androidx.browser:browser:1.2.0" + implementation 'androidx.navigation:navigation-fragment-ktx:2.3.2' + implementation 'androidx.navigation:navigation-ui-ktx:2.3.2' + implementation "androidx.browser:browser:1.3.0" implementation 'androidx.recyclerview:recyclerview:1.1.0' implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0" - implementation 'androidx.navigation:navigation-fragment-ktx:2.3.1' - implementation 'androidx.navigation:navigation-ui-ktx:2.3.1' - implementation 'androidx.paging:paging-runtime-ktx:3.0.0-alpha09' + implementation 'androidx.navigation:navigation-fragment-ktx:2.3.2' + implementation 'androidx.navigation:navigation-ui-ktx:2.3.2' + implementation 'androidx.paging:paging-runtime-ktx:3.0.0-alpha10' implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0' implementation 'androidx.lifecycle:lifecycle-viewmodel-savedstate:2.2.0' implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0" @@ -110,23 +110,23 @@ dependencies { implementation 'com.google.android.material:material:1.2.1' //Dagger (dependency injection) - implementation 'com.google.dagger:dagger-android:2.29.1' - implementation 'com.google.dagger:dagger-android-support:2.29.1' + implementation 'com.google.dagger:dagger-android:2.30.1' + implementation 'com.google.dagger:dagger-android-support:2.30.1' // if you use the support libraries - kapt 'com.google.dagger:dagger-android-processor:2.29.1' - kapt 'com.google.dagger:dagger-compiler:2.29.1' + kapt 'com.google.dagger:dagger-android-processor:2.30.1' + kapt 'com.google.dagger:dagger-compiler:2.30.1' implementation 'com.squareup.okhttp3:okhttp:4.9.0' implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0' - implementation 'io.reactivex.rxjava2:rxjava:2.2.19' + implementation 'io.reactivex.rxjava2:rxjava:2.2.20' implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' implementation 'com.github.connyduck:sparkbutton:4.0.0' implementation 'info.androidhive:imagefilters:1.0.7' - implementation 'com.github.yalantis:ucrop:2.2.5-native' + implementation 'com.github.yalantis:ucrop:2.2.6-native' implementation("com.github.bumptech.glide:glide:4.11.0") { exclude group: "com.android.support" @@ -141,13 +141,13 @@ dependencies { implementation 'androidx.legacy:legacy-support-v4:1.0.0' - implementation "com.mikepenz:materialdrawer:8.1.5" + implementation "com.mikepenz:materialdrawer:8.1.8" // Add for NavController support implementation "com.mikepenz:materialdrawer-nav:8.1.5" //iconics implementation "com.mikepenz:iconics-core:5.0.3" - implementation "com.mikepenz:materialdrawer-iconics:8.1.5" + implementation "com.mikepenz:materialdrawer-iconics:8.1.8" implementation "com.mikepenz:iconics-views:5.0.3" implementation 'com.mikepenz:google-material-typeface:3.0.1.4.original-kotlin@aar' From e71e5c304a655939de020fe0e8e33d1b418ae80f Mon Sep 17 00:00:00 2001 From: Matthieu <24-artectrex@users.noreply.shinice.net> Date: Tue, 8 Dec 2020 18:33:16 +0100 Subject: [PATCH 5/5] clean imports --- app/src/main/java/com/h/pixeldroid/LoginActivity.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/src/main/java/com/h/pixeldroid/LoginActivity.kt b/app/src/main/java/com/h/pixeldroid/LoginActivity.kt index 1214df8b..af3cd7f3 100644 --- a/app/src/main/java/com/h/pixeldroid/LoginActivity.kt +++ b/app/src/main/java/com/h/pixeldroid/LoginActivity.kt @@ -30,10 +30,8 @@ import okhttp3.HttpUrl import retrofit2.Call import retrofit2.Callback import retrofit2.Response -import retrofit2.Retrofit -import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory -import retrofit2.converter.gson.GsonConverterFactory import javax.inject.Inject + /** Overview of the flow of the login process: (boxes are requests done in parallel, since they do not depend on each other)