Commit a861a3a4 authored by Yusuke Iwaki's avatar Yusuke Iwaki

FIX #70 Merge branch 'twitter' into develop

parents 760fe05b 5661f5aa
......@@ -171,9 +171,9 @@ public class MethodCallHelper {
}
/**
* Login with GitHub OAuth.
* Login with OAuth.
*/
public Task<Void> loginWithGitHub(final String credentialToken,
public Task<Void> loginWithOAuth(final String credentialToken,
final String credentialSecret) {
return call("login", TIMEOUT_MS, () -> new JSONArray().put(new JSONObject()
.put("oauth", new JSONObject()
......
package chat.rocket.android.fragment.oauth;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.webkit.JavascriptInterface;
import android.webkit.WebView;
import chat.rocket.android.api.MethodCallHelper;
import chat.rocket.android.fragment.AbstractWebViewFragment;
import chat.rocket.android.helper.LogcatIfError;
import chat.rocket.android.model.ServerConfig;
import chat.rocket.android.model.ddp.MeteorLoginServiceConfiguration;
import chat.rocket.android.realm_helper.RealmStore;
import org.json.JSONException;
import org.json.JSONObject;
import timber.log.Timber;
abstract class AbstractOAuthFragment extends AbstractWebViewFragment {
protected String serverConfigId;
protected String hostname;
private String url;
private boolean resultOK;
protected abstract String getOAuthServiceName();
protected abstract String generateURL(MeteorLoginServiceConfiguration oauthConfig);
private boolean hasValidArgs(Bundle args) {
return args != null
&& args.containsKey("serverConfigId");
}
@Override public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = getArguments();
if (!hasValidArgs(args)) {
throw new IllegalArgumentException(
"serverConfigId required");
}
serverConfigId = args.getString("serverConfigId");
ServerConfig serverConfig = RealmStore.getDefault().executeTransactionForRead(realm ->
realm.where(ServerConfig.class).equalTo("serverConfigId", serverConfigId).findFirst());
MeteorLoginServiceConfiguration oauthConfig =
RealmStore.get(serverConfigId).executeTransactionForRead(realm ->
realm.where(MeteorLoginServiceConfiguration.class)
.equalTo("service", getOAuthServiceName())
.findFirst());
if (serverConfig == null || oauthConfig == null) {
throw new IllegalArgumentException(
"Invalid serverConfigId given,");
}
hostname = serverConfig.getHostname();
url = generateURL(oauthConfig);
}
@Override protected void navigateToInitialPage(WebView webview) {
if (TextUtils.isEmpty(url)) {
finish();
return;
}
resultOK = false;
webview.loadUrl(url);
webview.addJavascriptInterface(new JSInterface(result -> {
// onPageFinish is called twice... Should ignore latter one.
if (resultOK) {
return;
}
if (result != null && result.optBoolean("setCredentialToken", false)) {
try {
final String credentialToken = result.getString("credentialToken");
final String credentialSecret = result.getString("credentialSecret");
handleOAuthCallback(credentialToken, credentialSecret);
resultOK = true;
} catch (JSONException exception) {
Timber.e(exception, "failed to parse OAuth result.");
}
}
onOAuthCompleted();
}), "_rocketchet_hook");
}
@Override protected void onPageLoaded(WebView webview, String url) {
super.onPageLoaded(webview, url);
if (url.contains(hostname) && url.contains("_oauth/" + getOAuthServiceName() + "?close")) {
final String jsHookUrl = "javascript:"
+ "window._rocketchet_hook.handleConfig(document.getElementById('config').innerText);";
webview.loadUrl(jsHookUrl);
}
}
private interface JSInterfaceCallback {
void hanldeResult(@Nullable JSONObject result);
}
private static final class JSInterface {
private final JSInterfaceCallback jsInterfaceCallback;
JSInterface(JSInterfaceCallback callback) {
jsInterfaceCallback = callback;
}
@JavascriptInterface public void handleConfig(String config) {
try {
jsInterfaceCallback.hanldeResult(new JSONObject(config));
} catch (Exception exception) {
jsInterfaceCallback.hanldeResult(null);
}
}
}
private void handleOAuthCallback(final String credentialToken, final String credentialSecret) {
new MethodCallHelper(getContext(), serverConfigId)
.loginWithOAuth(credentialToken, credentialSecret)
.continueWith(new LogcatIfError());
}
protected void onOAuthCompleted() {
}
}
package chat.rocket.android.fragment.oauth;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Base64;
import android.webkit.JavascriptInterface;
import android.webkit.WebView;
import chat.rocket.android.fragment.AbstractWebViewFragment;
import chat.rocket.android.helper.LogcatIfError;
import chat.rocket.android.api.MethodCallHelper;
import chat.rocket.android.model.ServerConfig;
import chat.rocket.android.model.ddp.MeteorLoginServiceConfiguration;
import chat.rocket.android.realm_helper.RealmStore;
import java.nio.charset.Charset;
import okhttp3.HttpUrl;
import org.json.JSONException;
import org.json.JSONObject;
import timber.log.Timber;
public class GitHubOAuthFragment extends AbstractWebViewFragment {
private String serverConfigId;
private String hostname;
private String url;
private boolean resultOK;
public class GitHubOAuthFragment extends AbstractOAuthFragment {
/**
* create new Fragment with ServerConfig-ID.
......@@ -36,36 +21,12 @@ public class GitHubOAuthFragment extends AbstractWebViewFragment {
return fragment;
}
private boolean hasValidArgs(Bundle args) {
return args != null
&& args.containsKey("serverConfigId");
}
@Override public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = getArguments();
if (!hasValidArgs(args)) {
throw new IllegalArgumentException(
"serverConfigId required");
}
serverConfigId = args.getString("serverConfigId");
ServerConfig serverConfig = RealmStore.getDefault().executeTransactionForRead(realm ->
realm.where(ServerConfig.class).equalTo("serverConfigId", serverConfigId).findFirst());
MeteorLoginServiceConfiguration oauthConfig =
RealmStore.get(serverConfigId).executeTransactionForRead(realm ->
realm.where(MeteorLoginServiceConfiguration.class)
.equalTo("service", "github")
.findFirst());
if (serverConfig == null || oauthConfig == null) {
throw new IllegalArgumentException(
"Invalid serverConfigId given,");
}
hostname = serverConfig.getHostname();
url = generateURL(oauthConfig.getClientId());
@Override protected String getOAuthServiceName() {
return "github";
}
private String generateURL(String clientId) {
@Override protected String generateURL(MeteorLoginServiceConfiguration oauthConfig) {
final String clientId = oauthConfig.getClientId();
try {
String state = Base64.encodeToString(new JSONObject().put("loginStyle", "popup")
.put("credentialToken", "github" + System.currentTimeMillis())
......@@ -88,75 +49,4 @@ public class GitHubOAuthFragment extends AbstractWebViewFragment {
}
return null;
}
@Override protected void navigateToInitialPage(WebView webview) {
if (TextUtils.isEmpty(url)) {
finish();
return;
}
resultOK = false;
webview.loadUrl(url);
webview.addJavascriptInterface(new JSInterface(result -> {
// onPageFinish is called twice... Should ignore latter one.
if (resultOK) {
return;
}
if (result != null && result.optBoolean("setCredentialToken", false)) {
try {
final String credentialToken = result.getString("credentialToken");
final String credentialSecret = result.getString("credentialSecret");
handleOAuthCallback(credentialToken, credentialSecret);
resultOK = true;
} catch (JSONException exception) {
Timber.e(exception, "failed to parse OAuth result.");
}
}
onOAuthCompleted();
}), "_rocketchet_hook");
}
@Override protected void onPageLoaded(WebView webview, String url) {
super.onPageLoaded(webview, url);
if (url.contains(hostname) && url.contains("_oauth/github?close")) {
final String jsHookUrl = "javascript:"
+ "window._rocketchet_hook.handleConfig(document.getElementById('config').innerText);";
webview.loadUrl(jsHookUrl);
}
}
private interface JSInterfaceCallback {
void hanldeResult(@Nullable JSONObject result);
}
private static final class JSInterface {
private final JSInterfaceCallback jsInterfaceCallback;
JSInterface(JSInterfaceCallback callback) {
jsInterfaceCallback = callback;
}
@JavascriptInterface public void handleConfig(String config) {
try {
jsInterfaceCallback.hanldeResult(new JSONObject(config));
} catch (Exception exception) {
jsInterfaceCallback.hanldeResult(null);
}
}
}
private void handleOAuthCallback(final String credentialToken, final String credentialSecret) {
new MethodCallHelper(getContext(), serverConfigId)
.loginWithGitHub(credentialToken, credentialSecret)
.continueWith(new LogcatIfError());
}
private void onOAuthCompleted() {
}
}
package chat.rocket.android.fragment.oauth;
import android.os.Bundle;
import android.util.Base64;
import chat.rocket.android.model.ddp.MeteorLoginServiceConfiguration;
import java.nio.charset.Charset;
import org.json.JSONObject;
import timber.log.Timber;
public class TwitterOAuthFragment extends AbstractOAuthFragment {
/**
* create new Fragment with ServerConfig-ID.
*/
public static TwitterOAuthFragment create(final String serverConfigId) {
Bundle args = new Bundle();
args.putString("serverConfigId", serverConfigId);
TwitterOAuthFragment fragment = new TwitterOAuthFragment();
fragment.setArguments(args);
return fragment;
}
@Override protected String getOAuthServiceName() {
return "twitter";
}
@Override protected String generateURL(MeteorLoginServiceConfiguration oauthConfig) {
try {
String state = Base64.encodeToString(new JSONObject().put("loginStyle", "popup")
.put("credentialToken", "twitter" + System.currentTimeMillis())
.put("isCordova", true)
.toString()
.getBytes(Charset.forName("UTF-8")), Base64.NO_WRAP);
return "https://" + hostname + "/_oauth/twitter/?requestTokenAndRedirect=true&state=" + state;
} catch (Exception exception) {
Timber.e(exception, "failed to generate Twitter OAUth URL");
}
return null;
}
}
......@@ -8,6 +8,7 @@ import android.widget.TextView;
import chat.rocket.android.R;
import chat.rocket.android.fragment.oauth.GitHubOAuthFragment;
import chat.rocket.android.api.MethodCallHelper;
import chat.rocket.android.fragment.oauth.TwitterOAuthFragment;
import chat.rocket.android.helper.TextUtils;
import chat.rocket.android.model.ddp.MeteorLoginServiceConfiguration;
import chat.rocket.android.realm_helper.RealmListObserver;
......@@ -77,7 +78,7 @@ public class LoginFragment extends AbstractServerConfigFragment {
&& "twitter".equals(authProvider.getService())) {
hasTwitter = true;
btnTwitter.setOnClickListener(view -> {
showFragmentWithBackStack(TwitterOAuthFragment.create(serverConfigId));
});
}
if (!hasGitHub
......
......@@ -24,7 +24,6 @@
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginEnd="@dimen/margin_8"
android:enabled="false"
android:text="@string/fa_twitter"
android:textSize="16dp" />
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment