Skip to content

Commit

Permalink
Merge pull request orgzly-revived#208 from amberin/dropbox-refresh-token
Browse files Browse the repository at this point in the history
Dropbox repos: Use the new "refresh token" OAuth flow
  • Loading branch information
amberin authored Apr 3, 2024
2 parents 4731870 + eb9184d commit 4221bb2
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 106 deletions.
2 changes: 1 addition & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ android {
debug {
buildConfigField "boolean", "LOG_DEBUG", "true"

buildConfigField "String", "DROPBOX_TOKEN", gradle.ext.appProperties.getProperty("dropbox.token", '""')
buildConfigField "String", "DROPBOX_REFRESH_TOKEN", gradle.ext.appProperties.getProperty("dropbox.refresh_token", '""')
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.orgzly.android.prefs.AppPreferences;
import com.orgzly.android.util.MiscUtils;

import org.json.JSONObject;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
Expand All @@ -26,7 +27,12 @@ public void setUp() throws Exception {
super.setUp();
Assume.assumeTrue(BuildConfig.IS_DROPBOX_ENABLED);

AppPreferences.dropboxToken(context, BuildConfig.DROPBOX_TOKEN);
JSONObject mockSerializedDbxCredential = new JSONObject();
mockSerializedDbxCredential.put("access_token", "dummy");
mockSerializedDbxCredential.put("expires_at", System.currentTimeMillis());
mockSerializedDbxCredential.put("refresh_token", BuildConfig.DROPBOX_REFRESH_TOKEN);
mockSerializedDbxCredential.put("app_key", BuildConfig.DROPBOX_APP_KEY);
AppPreferences.dropboxSerializedCredential(context, mockSerializedDbxCredential.toString());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@

import android.net.Uri;

import com.orgzly.BuildConfig;
import com.orgzly.android.BookName;
import com.orgzly.android.LocalStorage;
import com.orgzly.android.OrgzlyTest;
import com.orgzly.android.db.entity.Book;
import com.orgzly.android.db.entity.BookView;
import com.orgzly.android.db.entity.NoteView;
import com.orgzly.android.db.entity.Repo;
import com.orgzly.android.prefs.AppPreferences;
import com.orgzly.android.sync.BookNamesake;
import com.orgzly.android.sync.BookSyncStatus;
import com.orgzly.android.util.EncodingDetect;
Expand Down Expand Up @@ -38,8 +36,6 @@ public class SyncTest extends OrgzlyTest {
@Before
public void setUp() throws Exception {
super.setUp();

AppPreferences.dropboxToken(context, BuildConfig.DROPBOX_TOKEN);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -892,13 +892,13 @@ public static boolean highlightEditedRichText(Context context) {
* Dropbox token.
*/

public static String dropboxToken(Context context) {
String key = context.getResources().getString(R.string.pref_key_dropbox_token);
public static String dropboxSerializedCredential(Context context) {
String key = context.getResources().getString(R.string.pref_key_dropbox_credential);
return getStateSharedPreferences(context).getString(key, null);
}

public static void dropboxToken(Context context, String value) {
String key = context.getResources().getString(R.string.pref_key_dropbox_token);
public static void dropboxSerializedCredential(Context context, String value) {
String key = context.getResources().getString(R.string.pref_key_dropbox_credential);
SharedPreferences.Editor editor = getStateSharedPreferences(context).edit();
if (value == null) {
editor.remove(key);
Expand Down
82 changes: 35 additions & 47 deletions app/src/main/java/com/orgzly/android/repos/DropboxClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import com.dropbox.core.DbxException;
import com.dropbox.core.DbxRequestConfig;
import com.dropbox.core.android.Auth;
import com.dropbox.core.json.JsonReadException;
import com.dropbox.core.oauth.DbxCredential;
import com.dropbox.core.v2.DbxClientV2;
import com.dropbox.core.v2.files.FileMetadata;
import com.dropbox.core.v2.files.FolderMetadata;
Expand Down Expand Up @@ -45,7 +47,8 @@ public class DropboxClient {

final private Context mContext;
final private long repoId;

final private DbxRequestConfig requestConfig;
private DbxCredential credential;
private DbxClientV2 dbxClient;

private boolean tryLinking = false;
Expand All @@ -55,14 +58,31 @@ public DropboxClient(Context context, long id) {

repoId = id;

requestConfig = getRequestConfig();

createClient();
}

private void createClient() {
String accessToken = getToken();
private DbxRequestConfig getRequestConfig() {
String userLocale = Locale.getDefault().toString();
String clientId = String.format("%s/%s",
BuildConfig.APPLICATION_ID, BuildConfig.VERSION_NAME);
return DbxRequestConfig
.newBuilder(clientId)
.withUserLocale(userLocale)
.build();
}

if (accessToken != null) {
dbxClient = getDbxClient(accessToken);
private void createClient() {
String serializedCredential = AppPreferences.dropboxSerializedCredential(mContext);
if (serializedCredential != null && serializedCredential.length() > 0) {
try {
credential =
DbxCredential.Reader.readFully(serializedCredential);
} catch (JsonReadException e) {
throw new RuntimeException(e);
}
dbxClient = new DbxClientV2(requestConfig, credential);
}
}

Expand All @@ -78,65 +98,33 @@ private void linkedOrThrow() throws IOException {

public void unlink() {
dbxClient = null;
deleteToken();
deleteCredential();
tryLinking = false;
}

public void beginAuthentication(Activity activity) {
tryLinking = true;
Auth.startOAuth2Authentication(activity, BuildConfig.DROPBOX_APP_KEY);
Auth.startOAuth2PKCE(activity, BuildConfig.DROPBOX_APP_KEY, requestConfig);
}

public boolean finishAuthentication() {
if (dbxClient == null && tryLinking) {
String accessToken = getToken();

if (accessToken == null) {
accessToken = Auth.getOAuth2Token();

if (accessToken != null) {
saveToken(accessToken);
}
}

if (accessToken != null) {
dbxClient = getDbxClient(accessToken);
credential = Auth.getDbxCredential();
if (credential != null) {
saveCredential();
createClient();
return true;
}
}

return false;
}

private DbxClientV2 getDbxClient(String accessToken) {
String userLocale = Locale.getDefault().toString();

String clientId = String.format("%s/%s",
BuildConfig.APPLICATION_ID, BuildConfig.VERSION_NAME);

DbxRequestConfig requestConfig = DbxRequestConfig
.newBuilder(clientId)
.withUserLocale(userLocale)
.build();

return new DbxClientV2(requestConfig, accessToken);
}

public void setToken(String token) {
saveToken(token);
createClient();
}

private void saveToken(String token) {
AppPreferences.dropboxToken(mContext, token);
}

public String getToken() {
return AppPreferences.dropboxToken(mContext);
private void saveCredential() {
AppPreferences.dropboxSerializedCredential(mContext, credential.toString());
}

private void deleteToken() {
AppPreferences.dropboxToken(mContext, null);
private void deleteCredential() {
AppPreferences.dropboxSerializedCredential(mContext, null);
}

public List<VersionedRook> getBooks(Uri repoUri) throws IOException {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package com.orgzly.android.ui.repo.dropbox

import android.annotation.SuppressLint
import android.app.Activity
import android.content.DialogInterface
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.text.TextUtils
import android.widget.EditText
import androidx.core.content.ContextCompat
import androidx.core.widget.ImageViewCompat
import androidx.lifecycle.Observer
Expand Down Expand Up @@ -60,11 +58,6 @@ class DropboxRepoActivity : CommonActivity() {
}
}

binding.activityRepoDropboxLinkButton.setOnLongClickListener {
editAccessToken()
true
}

// Not working when done in XML
binding.activityRepoDropboxDirectory.apply {
setHorizontallyScrolling(false)
Expand Down Expand Up @@ -125,47 +118,6 @@ class DropboxRepoActivity : CommonActivity() {
}
}

private fun editAccessToken() {
@SuppressLint("InflateParams")
val view = layoutInflater.inflate(R.layout.dialog_simple_one_liner, null, false)

val editView = view.findViewById<EditText>(R.id.dialog_input).apply {
setSelectAllOnFocus(true)

setHint(R.string.access_token)

client.token?.let {
setText(it)
}
}

alertDialog = MaterialAlertDialogBuilder(this)
.setView(view)
.setTitle(R.string.access_token)
.setPositiveButton(R.string.set) { _, _ ->
editView.text.toString().let { value ->
if (TextUtils.isEmpty(value)) {
client.unlink()
} else {
client.setToken(value)
}
}
updateDropboxLinkUnlinkButton()
}
.setNeutralButton(R.string.clear) { _, _ ->
client.unlink()
updateDropboxLinkUnlinkButton()
}
.setNegativeButton(R.string.cancel) { _, _ -> }
.create().apply {
setOnShowListener {
KeyboardUtils.openSoftKeyboard(editView)
}

show()
}
}

public override fun onResume() {
super.onResume()

Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values/prefs_keys.xml
Original file line number Diff line number Diff line change
Expand Up @@ -591,7 +591,7 @@
<string name="pref_key_clear_database" translatable="false">pref_key_clear_database</string>

<!-- State-type preferences, not changeable by user. They have no defaults. -->
<string name="pref_key_dropbox_token" translatable="false">pref_key_dropbox_token</string>
<string name="pref_key_dropbox_credential" translatable="false">pref_key_dropbox_token</string>
<string name="pref_key_is_getting_started_notebook_loaded" translatable="false">pref_key_is_getting_started_notebook_loaded</string>
<string name="pref_key_last_used_version_code" translatable="false">pref_key_last_used_version_code</string>
<string name="pref_key_last_successful_sync_time" translatable="false">pref_key_last_successful_sync_time</string>
Expand Down

0 comments on commit 4221bb2

Please sign in to comment.