From 1dc56ae41c10146312e51e5b4551852a8f3ca5d1 Mon Sep 17 00:00:00 2001 From: M66B Date: Fri, 20 Dec 2019 13:54:05 +0100 Subject: [PATCH] Replaced MSAL by OAuth --- app/build.gradle | 3 - .../java/eu/faircode/email/ActivitySetup.java | 508 +++++++++--------- .../java/eu/faircode/email/EmailProvider.java | 2 + .../java/eu/faircode/email/FragmentSetup.java | 29 +- app/src/main/res/values/strings.xml | 3 +- app/src/main/res/xml/providers.xml | 8 + 6 files changed, 275 insertions(+), 278 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index a390fef3a0..078d30d0d0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -334,9 +334,6 @@ dependencies { // // https://github.com/QuadFlask/colorpicker implementation "com.github.QuadFlask:colorpicker:$colorpicker_version" - // https://github.com/AzureAD/microsoft-authentication-library-for-android - implementation "com.microsoft.identity.client:msal:$msal_version" - // https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on implementation "org.bouncycastle:bcpkix-jdk15to18:$bouncycastle_version" //implementation "org.bouncycastle:bcmail-jdk15to18:$bouncycastle_version" diff --git a/app/src/main/java/eu/faircode/email/ActivitySetup.java b/app/src/main/java/eu/faircode/email/ActivitySetup.java index 2e9fd59655..4b89a130ad 100644 --- a/app/src/main/java/eu/faircode/email/ActivitySetup.java +++ b/app/src/main/java/eu/faircode/email/ActivitySetup.java @@ -66,14 +66,9 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.google.android.material.textfield.TextInputLayout; -import com.microsoft.identity.client.AuthenticationCallback; -import com.microsoft.identity.client.IAuthenticationResult; -import com.microsoft.identity.client.IMultipleAccountPublicClientApplication; -import com.microsoft.identity.client.IPublicClientApplication; -import com.microsoft.identity.client.PublicClientApplication; -import com.microsoft.identity.client.exception.MsalException; 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; @@ -81,6 +76,7 @@ import net.openid.appauth.AuthorizationService; import net.openid.appauth.AuthorizationServiceConfiguration; import net.openid.appauth.ClientAuthentication; import net.openid.appauth.ClientSecretPost; +import net.openid.appauth.NoClientAuthentication; import net.openid.appauth.ResponseTypeValues; import net.openid.appauth.TokenResponse; import net.openid.appauth.browser.BrowserBlacklist; @@ -328,7 +324,6 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac IntentFilter iff = new IntentFilter(); iff.addAction(ACTION_QUICK_GMAIL); iff.addAction(ACTION_QUICK_OAUTH); - iff.addAction(ACTION_QUICK_OUTLOOK); iff.addAction(ACTION_QUICK_SETUP); iff.addAction(ACTION_VIEW_ACCOUNTS); iff.addAction(ACTION_VIEW_IDENTITIES); @@ -1160,273 +1155,270 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac fragmentTransaction.commit(); } + private AuthorizationService getAuthorizationService() { + AppAuthConfiguration appAuthConfig = new AppAuthConfiguration.Builder() + .setBrowserMatcher(new BrowserBlacklist( + new VersionedBrowserMatcher( + Browsers.SBrowser.PACKAGE_NAME, + Browsers.SBrowser.SIGNATURE_SET, + true, + VersionRange.atMost("5.3") + ))) + .build(); + + return new AuthorizationService(this, appAuthConfig); + } + private void onOAuth(Intent intent) { - String name = intent.getStringExtra("name"); - for (EmailProvider provider : EmailProvider.loadProfiles(this)) - if (provider.name.equals(name) && provider.oauth != null) { - AppAuthConfiguration appAuthConfig = new AppAuthConfiguration.Builder() - .setBrowserMatcher(new BrowserBlacklist( - new VersionedBrowserMatcher( - Browsers.SBrowser.PACKAGE_NAME, - Browsers.SBrowser.SIGNATURE_SET, - true, - VersionRange.atMost("5.3") - ))) - .build(); - - AuthorizationService authService = new AuthorizationService(this, appAuthConfig); - - AuthorizationRequest authRequest = - new AuthorizationRequest.Builder( - new AuthorizationServiceConfiguration( - Uri.parse(provider.oauth.authorizationEndpoint), - Uri.parse(provider.oauth.tokenEndpoint)), - provider.oauth.clientId, - ResponseTypeValues.CODE, - Uri.parse(provider.oauth.redirectUri)) - .setScopes(provider.oauth.scopes) - .setState(name) - .build(); - - Intent authIntent = authService.getAuthorizationRequestIntent(authRequest); - startActivityForResult(authIntent, REQUEST_OAUTH); - - return; - } + try { + String name = intent.getStringExtra("name"); + for (EmailProvider provider : EmailProvider.loadProfiles(this)) + if (provider.name.equals(name) && provider.oauth != null) { + AuthorizationServiceConfiguration serviceConfig = new AuthorizationServiceConfiguration( + Uri.parse(provider.oauth.authorizationEndpoint), + Uri.parse(provider.oauth.tokenEndpoint)); + + AuthState authState = new AuthState(serviceConfig); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + prefs.edit().putString("oauth." + provider.name, authState.jsonSerializeString()).apply(); + + AuthorizationRequest authRequest = + new AuthorizationRequest.Builder( + serviceConfig, + provider.oauth.clientId, + ResponseTypeValues.CODE, + Uri.parse(provider.oauth.redirectUri)) + .setScopes(provider.oauth.scopes) + .setState(provider.name) + .build(); + + Intent authIntent = getAuthorizationService().getAuthorizationRequestIntent(authRequest); + startActivityForResult(authIntent, REQUEST_OAUTH); + + return; + } - Log.unexpectedError(getSupportFragmentManager(), - new IllegalArgumentException("Unknown provider=" + name)); + throw new IllegalArgumentException("Unknown provider=" + name); + } catch (Throwable ex) { + Log.unexpectedError(getSupportFragmentManager(), ex); + } } - private void onHandleOAuth(Intent data) { - AuthorizationResponse auth = AuthorizationResponse.fromIntent(data); - if (auth == null) { - AuthorizationException ex = AuthorizationException.fromIntent(data); + private void onHandleOAuth(@NonNull Intent data) { + try { + AuthorizationResponse auth = AuthorizationResponse.fromIntent(data); + if (auth == null) + throw AuthorizationException.fromIntent(data); + + for (EmailProvider provider : EmailProvider.loadProfiles(this)) + if (provider.name.equals(auth.state)) { + + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + final AuthState authState = AuthState.jsonDeserialize(prefs.getString("oauth." + provider.name, null)); + authState.update(auth, null); + prefs.edit().remove("oauth." + provider.name).apply(); + + ClientAuthentication clientAuth; + if (provider.oauth.clientSecret == null) + clientAuth = NoClientAuthentication.INSTANCE; + else + clientAuth = new ClientSecretPost(provider.oauth.clientSecret); + getAuthorizationService().performTokenRequest( + auth.createTokenExchangeRequest(), + clientAuth, + new AuthorizationService.TokenResponseCallback() { + @Override + public void onTokenRequestCompleted(TokenResponse access, AuthorizationException error) { + try { + if (access == null) + throw error; + + authState.update(access, null); + + Log.i("OAuth token provider=" + provider.name); + + if ("Outlook/Office365".equals(provider.name)) { + authState.performActionWithFreshTokens(getAuthorizationService(), new AuthState.AuthStateAction() { + @Override + public void execute(String accessToken, String idToken, AuthorizationException error) { + try { + if (error != null) + throw error; + + onOutlook(accessToken, idToken); + } catch (Throwable ex) { + Log.unexpectedError(getSupportFragmentManager(), ex); + } + } + }); + } else + throw new IllegalArgumentException("Unknown action provider=" + provider.name); + + } catch (Throwable ex) { + Log.unexpectedError(getSupportFragmentManager(), ex); + } + } + }); + + return; + } + + throw new IllegalArgumentException("Unknown state=" + auth.state); + } catch (Throwable ex) { Log.unexpectedError(getSupportFragmentManager(), ex); - return; } + } - for (EmailProvider provider : EmailProvider.loadProfiles(this)) - if (provider.name.equals(auth.state)) { - AuthorizationService authService = new AuthorizationService(this); - ClientAuthentication clientAuth = new ClientSecretPost(provider.oauth.clientSecret); - authService.performTokenRequest( - auth.createTokenExchangeRequest(), - clientAuth, - new AuthorizationService.TokenResponseCallback() { - @Override - public void onTokenRequestCompleted(TokenResponse access, AuthorizationException ex) { - if (access == null) { - Log.unexpectedError(getSupportFragmentManager(), ex); - return; - } + private void onOutlook(String accessToken, String idToken) { + Bundle args = new Bundle(); + args.putString("token", accessToken); - // access.accessToken - } - }); + new SimpleTask() { + @Override + protected JSONObject onExecute(Context context, Bundle args) throws Throwable { + String token = args.getString("token"); + + // https://docs.microsoft.com/en-us/graph/api/user-get?view=graph-rest-1.0&tabs=http#http-request + URL url = new URL("https://graph.microsoft.com/v1.0/me" + + "?$select=displayName,otherMails"); + Log.i("MSGraph fetching " + url); + + HttpURLConnection request = (HttpURLConnection) url.openConnection(); + request.setReadTimeout(15 * 1000); + request.setConnectTimeout(15 * 1000); + request.setRequestMethod("GET"); + request.setDoInput(true); + request.setRequestProperty("Authorization", "Bearer " + token); + request.setRequestProperty("Content-Type", "application/json"); + request.connect(); - return; + try { + Log.i("MSGraph getting response"); + String json = Helper.readStream(request.getInputStream(), StandardCharsets.UTF_8.name()); + return new JSONObject(json); + } finally { + request.disconnect(); + } } - Log.unexpectedError(getSupportFragmentManager(), - new IllegalArgumentException("Unknown state=" + auth.state)); - } + @Override + protected void onExecuted(Bundle args, JSONObject data) { + Log.i("MSGraph " + data); - private void onOutlook(Intent intent) { - PublicClientApplication.createMultipleAccountPublicClientApplication( - this, - R.raw.msal_config, - new IPublicClientApplication.IMultipleAccountApplicationCreatedListener() { - @Override - public void onCreated(IMultipleAccountPublicClientApplication msal) { - Log.i("MSAL app created"); - msal.acquireToken( - ActivitySetup.this, - // "openid", "offline_access", "profile", "email" - // https://docs.microsoft.com/en-us/graph/permissions-reference - new String[]{ - "openid", "offline_access", "profile", "email", - "User.Read", "Mail.ReadWrite", "Mail.Send", "MailboxSettings.ReadWrite"}, - new AuthenticationCallback() { - @Override - public void onSuccess(IAuthenticationResult result) { - Log.i("MSAL got token"); - - Bundle args = new Bundle(); - args.putString("token", result.getAccessToken()); - args.putString("id", result.getAccount().getId()); - args.putString("tenant", result.getAccount().getTenantId()); - Log.logBundle(args); - - Map claims = result.getAccount().getClaims(); - if (claims != null) - for (String key : claims.keySet()) - Log.i(key + "=" + claims.get(key)); - - new SimpleTask() { - @Override - protected JSONObject onExecute(Context context, Bundle args) throws Throwable { - String token = args.getString("token"); - - // https://docs.microsoft.com/en-us/graph/api/user-get?view=graph-rest-1.0&tabs=http#http-request - URL url = new URL("https://graph.microsoft.com/v1.0/me" + - "?$select=displayName,otherMails"); - Log.i("MSAL fetching " + url); - - HttpURLConnection request = (HttpURLConnection) url.openConnection(); - request.setReadTimeout(15 * 1000); - request.setConnectTimeout(15 * 1000); - request.setRequestMethod("GET"); - request.setDoInput(true); - request.setRequestProperty("Authorization", "Bearer " + token); - request.setRequestProperty("Content-Type", "application/json"); - request.connect(); - - try { - Log.i("MSAL getting response"); - String json = Helper.readStream(request.getInputStream(), StandardCharsets.UTF_8.name()); - return new JSONObject(json); - } finally { - request.disconnect(); - } - } - - @Override - protected void onExecuted(Bundle args, JSONObject data) { - Log.i("MSAL " + data); - - try { - JSONArray otherMails = data.getJSONArray("otherMails"); - - args.putString("displayName", data.getString("displayName")); - args.putString("email", (String) otherMails.get(0)); - - new SimpleTask() { - @Override - protected Void onExecute(Context context, Bundle args) throws Throwable { - String token = args.getString("token"); - String email = args.getString("email"); - String displayName = args.getString("displayName"); - - List folders; - - // https://msdn.microsoft.com/en-us/windows/desktop/dn440163 - String host = "imap-mail.outlook.com"; - int port = 993; - boolean starttls = false; - String user = email; - String password = token; - try (MailService iservice = new MailService(context, "imaps", null, false, true, true)) { - iservice.connect(host, port, MailService.AUTH_TYPE_OUTLOOK, user, password, null); - - folders = iservice.getFolders(); - - DB db = DB.getInstance(context); - try { - db.beginTransaction(); - - EntityAccount primary = db.account().getPrimaryAccount(); - - // Create account - EntityAccount account = new EntityAccount(); - - account.host = host; - account.starttls = starttls; - account.port = port; - account.auth_type = MailService.AUTH_TYPE_OUTLOOK; - account.user = user; - account.password = password; - - account.name = "OutLook"; - - account.synchronize = true; - account.primary = (primary == null); - - account.created = new Date().getTime(); - account.last_connected = account.created; - - account.id = db.account().insertAccount(account); - args.putLong("account", account.id); - EntityLog.log(context, "OutLook account=" + account.name); - - // Create folders - for (EntityFolder folder : folders) { - folder.account = account.id; - folder.id = db.folder().insertFolder(folder); - EntityLog.log(context, "OutLook folder=" + folder.name + " type=" + folder.type); - } - - // Set swipe left/right folder - for (EntityFolder folder : folders) - if (EntityFolder.TRASH.equals(folder.type)) - account.swipe_left = folder.id; - else if (EntityFolder.ARCHIVE.equals(folder.type)) - account.swipe_right = folder.id; - - db.account().updateAccount(account); - - // Create identity - EntityIdentity identity = new EntityIdentity(); - identity.name = displayName; - identity.email = user; - identity.account = account.id; - - identity.host = "smtp-mail.outlook.com"; - identity.starttls = true; - identity.port = 587; - identity.auth_type = MailService.AUTH_TYPE_OUTLOOK; - identity.user = user; - identity.password = password; - identity.synchronize = true; - identity.primary = true; - - identity.id = db.identity().insertIdentity(identity); - args.putLong("identity", identity.id); - EntityLog.log(context, "Gmail identity=" + identity.name + " email=" + identity.email); - - db.setTransactionSuccessful(); - } finally { - db.endTransaction(); - } - } - - return null; - } - - @Override - protected void onException(Bundle args, Throwable ex) { - - } - }.execute(ActivitySetup.this, args, "outlook:account"); - } catch (JSONException ex) { - Log.e(ex); - } - } + try { + JSONArray otherMails = data.getJSONArray("otherMails"); - @Override - protected void onException(Bundle args, Throwable ex) { - Log.unexpectedError(getSupportFragmentManager(), ex); - } - }.execute(ActivitySetup.this, args, "graph:profile"); - } + args.putString("displayName", data.getString("displayName")); + args.putString("email", (String) otherMails.get(0)); - @Override - public void onError(MsalException ex) { - Log.e(ex); - } + new SimpleTask() { + @Override + protected Void onExecute(Context context, Bundle args) throws Throwable { + String token = args.getString("token"); + String email = args.getString("email"); + String displayName = args.getString("displayName"); + + List folders; + + // https://msdn.microsoft.com/en-us/windows/desktop/dn440163 + String host = "imap-mail.outlook.com"; + int port = 993; + boolean starttls = false; + String user = email; + String password = token; + try (MailService iservice = new MailService(context, "imaps", null, false, true, true)) { + iservice.connect(host, port, MailService.AUTH_TYPE_OUTLOOK, user, password, null); + + folders = iservice.getFolders(); + + DB db = DB.getInstance(context); + try { + db.beginTransaction(); - @Override - public void onCancel() { - Log.w("MSAL cancelled"); + EntityAccount primary = db.account().getPrimaryAccount(); + + // Create account + EntityAccount account = new EntityAccount(); + + account.host = host; + account.starttls = starttls; + account.port = port; + account.auth_type = MailService.AUTH_TYPE_OUTLOOK; + account.user = user; + account.password = password; + + account.name = "OutLook"; + + account.synchronize = true; + account.primary = (primary == null); + + account.created = new Date().getTime(); + account.last_connected = account.created; + + account.id = db.account().insertAccount(account); + args.putLong("account", account.id); + EntityLog.log(context, "OutLook account=" + account.name); + + // Create folders + for (EntityFolder folder : folders) { + folder.account = account.id; + folder.id = db.folder().insertFolder(folder); + EntityLog.log(context, "OutLook folder=" + folder.name + " type=" + folder.type); } - }); - } - @Override - public void onError(MsalException ex) { - Log.e("MSAL", ex); - } - }); + // Set swipe left/right folder + for (EntityFolder folder : folders) + if (EntityFolder.TRASH.equals(folder.type)) + account.swipe_left = folder.id; + else if (EntityFolder.ARCHIVE.equals(folder.type)) + account.swipe_right = folder.id; + + db.account().updateAccount(account); + + // Create identity + EntityIdentity identity = new EntityIdentity(); + identity.name = displayName; + identity.email = user; + identity.account = account.id; + + identity.host = "smtp-mail.outlook.com"; + identity.starttls = true; + identity.port = 587; + identity.auth_type = MailService.AUTH_TYPE_OUTLOOK; + identity.user = user; + identity.password = password; + identity.synchronize = true; + identity.primary = true; + + identity.id = db.identity().insertIdentity(identity); + args.putLong("identity", identity.id); + EntityLog.log(context, "Gmail identity=" + identity.name + " email=" + identity.email); + + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + } + + return null; + } + + @Override + protected void onException(Bundle args, Throwable ex) { + + } + }.execute(ActivitySetup.this, args, "outlook:account"); + } catch (JSONException ex) { + Log.e(ex); + } + } + + @Override + protected void onException(Bundle args, Throwable ex) { + Log.unexpectedError(getSupportFragmentManager(), ex); + } + }.execute(ActivitySetup.this, args, "graph:profile"); + } private void onViewQuickSetup(Intent intent) { @@ -1580,8 +1572,6 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac onGmail(intent); else if (ACTION_QUICK_OAUTH.equals(action)) onOAuth(intent); - else if (ACTION_QUICK_OUTLOOK.equals(action)) - onOutlook(intent); else if (ACTION_QUICK_SETUP.equals(action)) onViewQuickSetup(intent); else if (ACTION_VIEW_ACCOUNTS.equals(action)) diff --git a/app/src/main/java/eu/faircode/email/EmailProvider.java b/app/src/main/java/eu/faircode/email/EmailProvider.java index 5386e23b81..0a2345f298 100644 --- a/app/src/main/java/eu/faircode/email/EmailProvider.java +++ b/app/src/main/java/eu/faircode/email/EmailProvider.java @@ -132,6 +132,7 @@ public class EmailProvider { provider.smtp.starttls = xml.getAttributeBooleanValue(null, "starttls", false); } else if ("oauth".equals(name)) { provider.oauth = new OAuth(); + provider.oauth.enabled = xml.getAttributeBooleanValue(null, "enabled", false); provider.oauth.clientId = xml.getAttributeValue(null, "clientId"); provider.oauth.clientSecret = xml.getAttributeValue(null, "clientSecret"); provider.oauth.scopes = xml.getAttributeValue(null, "scopes").split(","); @@ -661,6 +662,7 @@ public class EmailProvider { } public static class OAuth { + boolean enabled; String clientId; String clientSecret; String[] scopes; diff --git a/app/src/main/java/eu/faircode/email/FragmentSetup.java b/app/src/main/java/eu/faircode/email/FragmentSetup.java index f0bf724fce..2b8502ccec 100644 --- a/app/src/main/java/eu/faircode/email/FragmentSetup.java +++ b/app/src/main/java/eu/faircode/email/FragmentSetup.java @@ -166,22 +166,29 @@ public class FragmentSetup extends FragmentBase { public void onClick(View v) { PopupMenuLifecycle popupMenu = new PopupMenuLifecycle(getContext(), getViewLifecycleOwner(), btnQuick); - popupMenu.getMenu().add(Menu.NONE, R.string.title_setup_gmail, 1, R.string.title_setup_gmail); + int order = 1; + popupMenu.getMenu().add(Menu.NONE, R.string.title_setup_gmail, order++, R.string.title_setup_gmail); // Android 5 Lollipop does not support app links - if (BuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) - popupMenu.getMenu().add(Menu.NONE, R.string.title_setup_gmail_oauth, 2, R.string.title_setup_gmail_oauth); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) + for (EmailProvider provider : EmailProvider.loadProfiles(getContext())) + if (provider.oauth != null && (provider.oauth.enabled || BuildConfig.DEBUG)) + popupMenu.getMenu() + .add(Menu.NONE, -1, order++, getString(R.string.title_setup_oauth, provider.name)) + .setIntent(new Intent(ActivitySetup.ACTION_QUICK_OAUTH).putExtra("name", provider.name)); - if (BuildConfig.DEBUG) - popupMenu.getMenu().add(Menu.NONE, R.string.title_setup_outlook, 3, R.string.title_setup_outlook); - - popupMenu.getMenu().add(Menu.NONE, R.string.title_setup_activesync, 4, R.string.title_setup_activesync); - popupMenu.getMenu().add(Menu.NONE, R.string.title_setup_other, 5, R.string.title_setup_other); + popupMenu.getMenu().add(Menu.NONE, R.string.title_setup_activesync, order++, R.string.title_setup_activesync); + popupMenu.getMenu().add(Menu.NONE, R.string.title_setup_other, order++, R.string.title_setup_other); popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext()); + if (item.getIntent() != null) { + lbm.sendBroadcast(item.getIntent()); + return true; + } + switch (item.getItemId()) { case R.string.title_setup_gmail: if (Helper.hasValidFingerprint(getContext())) @@ -189,12 +196,6 @@ public class FragmentSetup extends FragmentBase { else ToastEx.makeText(getContext(), R.string.title_setup_gmail_support, Toast.LENGTH_LONG).show(); return true; - case R.string.title_setup_gmail_oauth: - lbm.sendBroadcast(new Intent(ActivitySetup.ACTION_QUICK_OAUTH).putExtra("name", "Gmail")); - return true; - case R.string.title_setup_outlook: - lbm.sendBroadcast(new Intent(ActivitySetup.ACTION_QUICK_OUTLOOK)); - return true; case R.string.title_setup_activesync: Helper.viewFAQ(getContext(), 133); return true; diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 44e59389bc..ab5cc95578 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -140,8 +140,7 @@ Wizard Go \'back\' to go to the inbox Gmail - Gmail OAuth - Outlook + %1$s (OAuth) Exchange ActiveSync Other provider Authorizing Google accounts will work in official versions only because Android checks the app signature diff --git a/app/src/main/res/xml/providers.xml b/app/src/main/res/xml/providers.xml index 5e8b94c14c..7a33726346 100644 --- a/app/src/main/res/xml/providers.xml +++ b/app/src/main/res/xml/providers.xml @@ -18,6 +18,7 @@ authorizationEndpoint="https://accounts.google.com/o/oauth2/v2/auth" clientId="803253368361-574lor1js3csqif9nogkhk5m7688af3c.apps.googleusercontent.com" clientSecret="9iyiDx1LEfpg3fpH6DqzoIcG" + enabled="false" redirectUri="https://email.faircode.eu/oauth/" scopes="https://mail.google.com/" tokenEndpoint="https://oauth2.googleapis.com/token" /> @@ -38,6 +39,13 @@ host="smtp.office365.com" port="587" starttls="true" /> +