From ef9bed3cd36324155827ac67d0104e7e014ea296 Mon Sep 17 00:00:00 2001 From: M66B Date: Tue, 13 Jun 2023 07:45:23 +0200 Subject: [PATCH] Prepare daily Outlook contacts download --- .../java/eu/faircode/email/FragmentSetup.java | 89 +++++++++++-------- app/src/main/java/eu/faircode/email/Log.java | 2 + .../eu/faircode/email/MicrosoftGraph.java | 12 ++- 3 files changed, 64 insertions(+), 39 deletions(-) diff --git a/app/src/main/java/eu/faircode/email/FragmentSetup.java b/app/src/main/java/eu/faircode/email/FragmentSetup.java index 13487d65e7..1a62cf8b1d 100644 --- a/app/src/main/java/eu/faircode/email/FragmentSetup.java +++ b/app/src/main/java/eu/faircode/email/FragmentSetup.java @@ -73,6 +73,7 @@ import androidx.preference.PreferenceManager; import com.google.android.material.snackbar.Snackbar; import net.openid.appauth.AppAuthConfiguration; +import net.openid.appauth.AuthState; import net.openid.appauth.AuthorizationException; import net.openid.appauth.AuthorizationRequest; import net.openid.appauth.AuthorizationResponse; @@ -1274,6 +1275,18 @@ public class FragmentSetup extends FragmentBase implements SharedPreferences.OnS String user = args.getString("user"); EmailProvider provider = EmailProvider.getProvider(context, "outlookgraph"); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + prefs.edit().putBoolean("suggest_sent", true).apply(); + + if (BuildConfig.DEBUG) { + String json = prefs.getString("graph.contacts." + account, null); + if (!TextUtils.isEmpty(json)) { + args.putString("authState", json); + taskGraph.execute(this, args, "graph:contacts"); + return; + } + } + AppAuthConfiguration appAuthConfig = new AppAuthConfiguration.Builder() .build(); AuthorizationService authService = new AuthorizationService(context, appAuthConfig); @@ -1318,6 +1331,7 @@ public class FragmentSetup extends FragmentBase implements SharedPreferences.OnS throw ex; } + final AuthState authState = new AuthState(auth, null); final EmailProvider provider = EmailProvider.getProvider(context, "outlookgraph"); AuthorizationService authService = new AuthorizationService(context); @@ -1353,6 +1367,7 @@ public class FragmentSetup extends FragmentBase implements SharedPreferences.OnS if (access == null || access.accessToken == null) throw new IllegalStateException("No access token"); + authState.update(access, null); EntityLog.log(context, "Graph/contacts got token"); int semi = auth.request.state.lastIndexOf(':'); @@ -1360,43 +1375,9 @@ public class FragmentSetup extends FragmentBase implements SharedPreferences.OnS Bundle args = new Bundle(); args.putLong("account", account); - args.putString("accessToken", access.accessToken); - - new SimpleTask() { - @Override - protected Integer onExecute(Context context, Bundle args) throws Throwable { - long account = args.getLong("account"); - String accessToken = args.getString("accessToken"); - - return MicrosoftGraph.downloadContacts(context, account, accessToken); - } - - @Override - protected void onExecuted(Bundle args, @NonNull Integer count) { - EntityLog.log(context, "Graph/contacts count=" + count); - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - prefs.edit().putBoolean("suggest_sent", true).apply(); - - NumberFormat NF = NumberFormat.getInstance(); - String msg = getString(R.string.title_setup_import_graph_result, NF.format(count)); + args.putString("authState", authState.jsonSerializeString()); - final Snackbar snackbar = Snackbar.make(view, msg, Snackbar.LENGTH_INDEFINITE) - .setGestureInsetBottomIgnored(true); - snackbar.setAction(android.R.string.ok, new View.OnClickListener() { - @Override - public void onClick(View view) { - snackbar.dismiss(); - } - }); - snackbar.show(); - } - - @Override - protected void onException(Bundle args, Throwable ex) { - EntityLog.log(context, "Graph/contacts ex=" + Log.formatThrowable(ex, false)); - Log.unexpectedError(getParentFragmentManager(), ex); - } - }.execute(FragmentSetup.this, args, "graph:contacts"); + taskGraph.execute(FragmentSetup.this, args, "graph:contacts"); } catch (Throwable ex) { Log.unexpectedError(getParentFragmentManager(), ex); } @@ -1408,6 +1389,42 @@ public class FragmentSetup extends FragmentBase implements SharedPreferences.OnS } } + private final SimpleTask taskGraph = new SimpleTask() { + @Override + protected Integer onExecute(Context context, Bundle args) throws Throwable { + long account = args.getLong("account"); + String json = args.getString("authState"); + AuthState authState = AuthState.jsonDeserialize(json); + + return MicrosoftGraph.downloadContacts(context, account, authState); + } + + @Override + protected void onExecuted(Bundle args, @NonNull Integer count) { + final Context context = getContext(); + EntityLog.log(context, "Graph/contacts count=" + count); + + NumberFormat NF = NumberFormat.getInstance(); + String msg = getString(R.string.title_setup_import_graph_result, NF.format(count)); + + final Snackbar snackbar = Snackbar.make(view, msg, Snackbar.LENGTH_INDEFINITE) + .setGestureInsetBottomIgnored(true); + snackbar.setAction(android.R.string.ok, new View.OnClickListener() { + @Override + public void onClick(View view) { + snackbar.dismiss(); + } + }); + snackbar.show(); + } + + @Override + protected void onException(Bundle args, Throwable ex) { + EntityLog.log(getContext(), "Graph/contacts ex=" + Log.formatThrowable(ex, false)); + Log.unexpectedError(getParentFragmentManager(), ex); + } + }; + private ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() { @Override public void onAvailable(Network network) { diff --git a/app/src/main/java/eu/faircode/email/Log.java b/app/src/main/java/eu/faircode/email/Log.java index b82d4079b6..28b236195a 100644 --- a/app/src/main/java/eu/faircode/email/Log.java +++ b/app/src/main/java/eu/faircode/email/Log.java @@ -2289,6 +2289,8 @@ public class Log { value = "[redacted]"; else if (key != null && key.startsWith("oauth.")) value = "[redacted]"; + else if (key != null && key.startsWith("graph.contacts.")) + value = "[redacted]"; size += write(os, key + "=" + value + "\r\n"); } diff --git a/app/src/main/java/eu/faircode/email/MicrosoftGraph.java b/app/src/main/java/eu/faircode/email/MicrosoftGraph.java index 47414e3b9d..794c972e7f 100644 --- a/app/src/main/java/eu/faircode/email/MicrosoftGraph.java +++ b/app/src/main/java/eu/faircode/email/MicrosoftGraph.java @@ -57,7 +57,7 @@ public class MicrosoftGraph { db.identity().setIdentityState(ident.id, "connecting"); AuthState authState = AuthState.jsonDeserialize(ident.password); - ServiceAuthenticator.OAuthRefresh(context, ident.provider, ident.auth_type, ident.user, authState, false); + ServiceAuthenticator.OAuthRefresh(context, ident.provider, ident.auth_type, ident.user, authState, true); Long expiration = authState.getAccessTokenExpirationTime(); if (expiration != null) EntityLog.log(context, ident.user + " token expiration=" + new Date(expiration)); @@ -124,10 +124,16 @@ public class MicrosoftGraph { } } - static int downloadContacts(Context context, long account, String accessToken) throws IOException, JSONException { + static int downloadContacts(Context context, long account, AuthState authState) throws IOException, JSONException, MessagingException { int count = 0; DB db = DB.getInstance(context); + ServiceAuthenticator.OAuthRefresh(context, + "outlookgraph", ServiceAuthenticator.AUTH_TYPE_GRAPH, "contacts", authState, BuildConfig.DEBUG); + + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + prefs.edit().putString("graph.contacts." + account, authState.jsonSerializeString()).apply(); + // https://learn.microsoft.com/en-us/graph/api/user-list-contacts?view=graph-rest-1.0&tabs=http URL url = new URL(MicrosoftGraph.GRAPH_ENDPOINT + "contacts"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); @@ -135,7 +141,7 @@ public class MicrosoftGraph { connection.setReadTimeout(GRAPH_TIMEOUT * 1000); connection.setConnectTimeout(GRAPH_TIMEOUT * 1000); ConnectionHelper.setUserAgent(context, connection); - connection.setRequestProperty("Authorization", "Bearer " + accessToken); + connection.setRequestProperty("Authorization", "Bearer " + authState.getAccessToken()); connection.connect(); try {