mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2026-07-31 07:44:24 +02:00
Endurain: Improve token refresh logic
This commit is contained in:
+16
-12
@@ -25,6 +25,8 @@ import nodomain.freeyourgadget.gadgetbridge.GBApplication
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.R
|
import nodomain.freeyourgadget.gadgetbridge.R
|
||||||
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractPreferenceFragment
|
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractPreferenceFragment
|
||||||
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractSettingsActivityV2
|
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractSettingsActivityV2
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.GB
|
||||||
|
|
||||||
class EndurainPreferencesActivity : AbstractSettingsActivityV2() {
|
class EndurainPreferencesActivity : AbstractSettingsActivityV2() {
|
||||||
|
|
||||||
@@ -45,14 +47,16 @@ class EndurainPreferencesActivity : AbstractSettingsActivityV2() {
|
|||||||
updateLogoutPreferenceVisibility()
|
updateLogoutPreferenceVisibility()
|
||||||
setupLoginResultListener()
|
setupLoginResultListener()
|
||||||
|
|
||||||
// Refresh auth token
|
// Refresh tokens
|
||||||
val vm: EndurainSetupViewModel by viewModels()
|
val vm: EndurainSetupViewModel by viewModels()
|
||||||
val server = GBApplication.getPrefs().preferences.getString("endurain_server", null)
|
val server = GBApplication.getPrefs().preferences.getString("endurain_server", null)
|
||||||
if (server != null) {
|
if (server != null) {
|
||||||
vm.performTokenRefresh(server) {
|
if (vm.tokenManager.isAccessTokenExpired()) {
|
||||||
activity?.runOnUiThread {
|
vm.performTokenRefresh(server) {
|
||||||
updateStatus()
|
activity?.runOnUiThread {
|
||||||
updateLogoutPreferenceVisibility()
|
updateStatus()
|
||||||
|
updateLogoutPreferenceVisibility()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vm.fetchServerVersion(server) {
|
vm.fetchServerVersion(server) {
|
||||||
@@ -106,29 +110,29 @@ class EndurainPreferencesActivity : AbstractSettingsActivityV2() {
|
|||||||
vm.logout { success ->
|
vm.logout { success ->
|
||||||
activity?.runOnUiThread {
|
activity?.runOnUiThread {
|
||||||
if (success) {
|
if (success) {
|
||||||
Toast.makeText(requireContext(), "Logged out successfully", Toast.LENGTH_SHORT).show()
|
GB.toast("Logged out successfully", Toast.LENGTH_SHORT, GB.INFO)
|
||||||
updateStatus()
|
updateStatus()
|
||||||
updateLogoutPreferenceVisibility()
|
updateLogoutPreferenceVisibility()
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(requireContext(), "Logout failed", Toast.LENGTH_SHORT).show()
|
GB.toast("Logout failed", Toast.LENGTH_SHORT, GB.WARN)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateLogoutPreferenceVisibility() {
|
private fun updateLogoutPreferenceVisibility() {
|
||||||
findPreference<Preference>("pref_key_log_out")?.isVisible = vm.isLoggedIn()
|
findPreference<Preference>("pref_key_log_out")?.isVisible = vm.tokenManager.isLoggedIn()
|
||||||
findPreference<Preference>("pref_key_log_in")?.isVisible = !vm.isLoggedIn()
|
findPreference<Preference>("pref_key_log_in")?.isVisible = !vm.tokenManager.isLoggedIn()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateStatus() {
|
private fun updateStatus() {
|
||||||
val statusPref = findPreference<Preference>("pref_key_status")
|
val statusPref = findPreference<Preference>("pref_key_status")
|
||||||
val server = GBApplication.getPrefs().preferences.getString("endurain_server", null)
|
val server = GBApplication.getPrefs().preferences.getString("endurain_server", null)
|
||||||
val tokenExpiresAt = vm.getTokenExpiresAt()
|
val tokenExpiresAt = DateTimeUtils.parseTimeStamp(vm.tokenManager.getRefreshTokenExpiresAt())
|
||||||
|
|
||||||
var summaryText = "Not logged in, integration is disabled"
|
var summaryText = "Not logged in, integration is disabled"
|
||||||
if (vm.isLoggedIn() && server != null) {
|
if (vm.tokenManager.isLoggedIn() && server != null) {
|
||||||
summaryText = "Logged in to $server\nAuth token expires: $tokenExpiresAt"
|
summaryText = "Logged in to $server\nRefresh token expires: $tokenExpiresAt"
|
||||||
}
|
}
|
||||||
if (vm.serverVersion != null) {
|
if (vm.serverVersion != null) {
|
||||||
summaryText += "\nServer version: ${vm.serverVersion}"
|
summaryText += "\nServer version: ${vm.serverVersion}"
|
||||||
|
|||||||
+3
-17
@@ -27,7 +27,6 @@ import java.util.Date
|
|||||||
class EndurainSetupViewModel(application: Application) : AndroidViewModel(application) {
|
class EndurainSetupViewModel(application: Application) : AndroidViewModel(application) {
|
||||||
|
|
||||||
private val LOG = LoggerFactory.getLogger(EndurainSetupViewModel::class.java)
|
private val LOG = LoggerFactory.getLogger(EndurainSetupViewModel::class.java)
|
||||||
private val tokenManager = EndurainTokenManager(application)
|
|
||||||
private lateinit var apiClient: EndurainApiClient
|
private lateinit var apiClient: EndurainApiClient
|
||||||
|
|
||||||
enum class Step {
|
enum class Step {
|
||||||
@@ -38,6 +37,7 @@ class EndurainSetupViewModel(application: Application) : AndroidViewModel(applic
|
|||||||
SSO_LOGIN
|
SSO_LOGIN
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val tokenManager = EndurainTokenManager(application)
|
||||||
var step = Step.SERVER
|
var step = Step.SERVER
|
||||||
var server = ""
|
var server = ""
|
||||||
var localLoginEnabled = false
|
var localLoginEnabled = false
|
||||||
@@ -45,7 +45,6 @@ class EndurainSetupViewModel(application: Application) : AndroidViewModel(applic
|
|||||||
var pendingMfaUsername: String? = null
|
var pendingMfaUsername: String? = null
|
||||||
var serverVersion: String? = null
|
var serverVersion: String? = null
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch server version
|
* Fetch server version
|
||||||
*/
|
*/
|
||||||
@@ -57,9 +56,10 @@ class EndurainSetupViewModel(application: Application) : AndroidViewModel(applic
|
|||||||
try {
|
try {
|
||||||
apiClient = EndurainApiClient(serverUrl, tokenManager)
|
apiClient = EndurainApiClient(serverUrl, tokenManager)
|
||||||
serverVersion = apiClient.fetchVersion()
|
serverVersion = apiClient.fetchVersion()
|
||||||
|
callback(true)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
LOG.error("Fetching server version error", e)
|
LOG.error("Fetching server version error", e)
|
||||||
callback(true)
|
callback(false)
|
||||||
}
|
}
|
||||||
}.start()
|
}.start()
|
||||||
}
|
}
|
||||||
@@ -224,20 +224,6 @@ class EndurainSetupViewModel(application: Application) : AndroidViewModel(applic
|
|||||||
}.start()
|
}.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if user is currently logged in
|
|
||||||
*/
|
|
||||||
fun isLoggedIn(): Boolean {
|
|
||||||
return tokenManager.getAccessToken() != null && !tokenManager.isTokenExpired()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get token expiry date
|
|
||||||
*/
|
|
||||||
fun getTokenExpiresAt(): Date {
|
|
||||||
return DateTimeUtils.parseTimeStamp(tokenManager.getAccessTokenExpiresAt())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logout and clear tokens
|
* Logout and clear tokens
|
||||||
*/
|
*/
|
||||||
|
|||||||
+20
-8
@@ -38,18 +38,30 @@ class EndurainTokenManager(context: Context) {
|
|||||||
sharedPreferences.edit {
|
sharedPreferences.edit {
|
||||||
putString("access_token", accessToken)
|
putString("access_token", accessToken)
|
||||||
.putString("refresh_token", refreshToken)
|
.putString("refresh_token", refreshToken)
|
||||||
.putInt("expires_at", accessTokenExpiresAt)
|
.putInt("access_token_expires_at", accessTokenExpiresAt)
|
||||||
|
.putInt("refresh_token_expires_at",
|
||||||
|
((System.currentTimeMillis() / 1000) + (7 * 24 * 60 * 60)).toInt()
|
||||||
|
) // FIXME: 7 days is the Endurain default for refresh token expiry
|
||||||
|
// https://github.com/endurain-project/endurain/issues/514
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getAccessToken(): String? = sharedPreferences.getString("access_token", null)
|
|
||||||
fun getRefreshToken(): String? = sharedPreferences.getString("refresh_token", null)
|
|
||||||
fun getAccessTokenExpiresAt(): Int = sharedPreferences.getInt("expires_at", 0)
|
|
||||||
fun isTokenExpired(): Boolean {
|
|
||||||
return (System.currentTimeMillis() / 1000) >= getAccessTokenExpiresAt()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun clearTokens() {
|
fun clearTokens() {
|
||||||
sharedPreferences.edit { clear() }
|
sharedPreferences.edit { clear() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getAccessToken(): String? = sharedPreferences.getString("access_token", null)
|
||||||
|
fun getAccessTokenExpiresAt(): Int = sharedPreferences.getInt("access_token_expires_at", 0)
|
||||||
|
fun getRefreshToken(): String? = sharedPreferences.getString("refresh_token", null)
|
||||||
|
fun getRefreshTokenExpiresAt(): Int = sharedPreferences.getInt("refresh_token_expires_at", 0)
|
||||||
|
|
||||||
|
fun isLoggedIn(): Boolean {
|
||||||
|
return getRefreshToken() != null && !isRefreshTokenExpired()
|
||||||
|
}
|
||||||
|
fun isAccessTokenExpired(): Boolean {
|
||||||
|
return (System.currentTimeMillis() / 1000) >= getAccessTokenExpiresAt()
|
||||||
|
}
|
||||||
|
fun isRefreshTokenExpired(): Boolean {
|
||||||
|
return (System.currentTimeMillis() / 1000) >= getRefreshTokenExpiresAt()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+20
-15
@@ -61,7 +61,6 @@ import nodomain.freeyourgadget.gadgetbridge.activities.ActivitySummariesChartFra
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.activities.charts.DurationXLabelFormatter
|
import nodomain.freeyourgadget.gadgetbridge.activities.charts.DurationXLabelFormatter
|
||||||
import nodomain.freeyourgadget.gadgetbridge.activities.endurain.EndurainApiClient
|
import nodomain.freeyourgadget.gadgetbridge.activities.endurain.EndurainApiClient
|
||||||
import nodomain.freeyourgadget.gadgetbridge.activities.endurain.EndurainSetupViewModel
|
import nodomain.freeyourgadget.gadgetbridge.activities.endurain.EndurainSetupViewModel
|
||||||
import nodomain.freeyourgadget.gadgetbridge.activities.endurain.EndurainTokenManager
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.activities.fit.FitViewerActivity
|
import nodomain.freeyourgadget.gadgetbridge.activities.fit.FitViewerActivity
|
||||||
import nodomain.freeyourgadget.gadgetbridge.activities.workouts.charts.ChartDataRepository
|
import nodomain.freeyourgadget.gadgetbridge.activities.workouts.charts.ChartDataRepository
|
||||||
import nodomain.freeyourgadget.gadgetbridge.activities.workouts.charts.DefaultWorkoutCharts
|
import nodomain.freeyourgadget.gadgetbridge.activities.workouts.charts.DefaultWorkoutCharts
|
||||||
@@ -639,13 +638,7 @@ class WorkoutDetailsFragment : Fragment(), MenuProvider {
|
|||||||
|
|
||||||
val endurainVm: EndurainSetupViewModel by viewModels()
|
val endurainVm: EndurainSetupViewModel by viewModels()
|
||||||
val server = GBApplication.getPrefs().preferences.getString("endurain_server", null)
|
val server = GBApplication.getPrefs().preferences.getString("endurain_server", null)
|
||||||
if (server != null) {
|
overflowMenu?.findItem(R.id.activity_action_upload_to_endurain)?.isVisible = hasGpx && server != null && endurainVm.tokenManager.isLoggedIn()
|
||||||
endurainVm.performTokenRefresh(server) {
|
|
||||||
activity?.runOnUiThread {
|
|
||||||
overflowMenu?.findItem(R.id.activity_action_upload_to_endurain)?.isVisible = hasGpx && endurainVm.isLoggedIn()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun takeSharedScreenshot() {
|
private fun takeSharedScreenshot() {
|
||||||
@@ -761,14 +754,26 @@ class WorkoutDetailsFragment : Fragment(), MenuProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val tokenManager = EndurainTokenManager(requireContext())
|
val endurainVm: EndurainSetupViewModel by viewModels()
|
||||||
val serverUrl = GBApplication.getPrefs().preferences.getString("endurain_server", null)
|
val serverUrl = GBApplication.getPrefs().preferences.getString("endurain_server", null)
|
||||||
val apiClient = EndurainApiClient(serverUrl!!, tokenManager)
|
val apiClient = EndurainApiClient(serverUrl!!, endurainVm.tokenManager)
|
||||||
apiClient.uploadActivity(gpxFile) { success ->
|
endurainVm.performTokenRefresh(serverUrl) {
|
||||||
if (success)
|
apiClient.uploadActivity(gpxFile) { success ->
|
||||||
GB.toast("Successfully uploaded to Endurain", Toast.LENGTH_SHORT, GB.INFO)
|
activity?.runOnUiThread {
|
||||||
else
|
if (success)
|
||||||
GB.toast("Error while uploading to Endurain", Toast.LENGTH_SHORT, GB.INFO)
|
GB.toast(
|
||||||
|
"Successfully uploaded to Endurain",
|
||||||
|
Toast.LENGTH_SHORT,
|
||||||
|
GB.INFO
|
||||||
|
)
|
||||||
|
else
|
||||||
|
GB.toast(
|
||||||
|
"Error while uploading to Endurain",
|
||||||
|
Toast.LENGTH_SHORT,
|
||||||
|
GB.INFO
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
GB.toast(
|
GB.toast(
|
||||||
|
|||||||
Reference in New Issue
Block a user