package io.scal.secureshareui.login;
import timber.log.Timber;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import org.scribe.builder.ServiceBuilder;
import org.scribe.builder.api.ZTApi;
import org.scribe.builder.api.ZTTestApi;
import org.scribe.model.Token;
import org.scribe.model.Verifier;
import org.scribe.oauth.OAuthService;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import ch.boye.httpclientandroidlib.Header;
import ch.boye.httpclientandroidlib.HttpHost;
import ch.boye.httpclientandroidlib.HttpResponse;
import ch.boye.httpclientandroidlib.NameValuePair;
import ch.boye.httpclientandroidlib.client.ClientProtocolException;
import ch.boye.httpclientandroidlib.client.entity.UrlEncodedFormEntity;
import ch.boye.httpclientandroidlib.client.methods.HttpPost;
import ch.boye.httpclientandroidlib.conn.params.ConnRoutePNames;
import ch.boye.httpclientandroidlib.message.BasicNameValuePair;
import info.guardianproject.netcipher.client.StrongHttpsClient;
import info.guardianproject.netcipher.proxy.OrbotHelper;
import io.scal.secureshareui.controller.SiteController;
import io.scal.secureshareuilibrary.R;
/**
* Created by mnbogner on 3/25/15.
*/
public class ZTLoginActivity extends LockableActivity {
private static final String TAG = "ZTLoginActivity";
private static final int CODE = 0; // NEED A REAL VALUE?
private String mClientId;
private String mClientSecret;
private Token mRequestToken = null;
private Verifier mAccessVerifier = null;
private Token mAccessToken = null;
private OAuthService service;
private StrongHttpsClient mClient;
private boolean proxySet = false;
private int mAccessResult = RESULT_CANCELED;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mClientId = getString(R.string.zt_key);
mClientSecret = getString(R.string.zt_secret);
service = new ServiceBuilder()
.provider(ZTApi.class)
.apiKey(mClientId)
.apiSecret(mClientSecret)
.build();
GetAuthorizationUrlTask gauTask = new GetAuthorizationUrlTask(this);
gauTask.execute();
}
class GetAuthorizationUrlTask extends AsyncTask<String, String, String> {
private ZTLoginActivity ztla;
public GetAuthorizationUrlTask(ZTLoginActivity ztla) {
this.ztla = ztla;
}
@Override
protected String doInBackground(String... params) {
String authorizationUrl = ztla.getAuthorizationUrl();
return authorizationUrl;
}
protected void onPostExecute(String result) {
ztla.startZTWebActivity(result);
}
}
public String getAuthorizationUrl() {
Timber.d("GETTING REQUEST TOKEN...");
//
Map<String, String> parameters = service.getRequestParameters();
StrongHttpsClient client = getHttpClientInstance();
// check for tor
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
boolean useTor = settings.getBoolean("pusetor", false);
if (useTor) {
if ((!OrbotHelper.isOrbotInstalled(this)) || (!OrbotHelper.isOrbotRunning(this))) {
Timber.e("TOR SELECTED BUT ORBOT IS INACTIVE (ABORTING)");
return null;
} else {
Timber.e("TOR SELECTED, HOST " + getString(R.string.zt_tor_host) + ", PORT " + getString(R.string.zt_tor_port) + " (SETTING PROXY)");
String host = getString(R.string.zt_tor_host);
int port = Integer.parseInt(getString(R.string.zt_tor_port));
HttpHost proxyHost = new HttpHost(host, port, "http");
client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxyHost);
proxySet = true;
// set proxy for scribe oauth service
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port));
service.setProxy(proxy);
}
} else {
if (proxySet) {
Timber.d("TOR NOT SELECTED (CLEARING PROXY)");
client.getParams().removeParameter(ConnRoutePNames.DEFAULT_PROXY);
proxySet = false;
// un-set proxy for scribe oauth service
service.setProxy(null);
} else {
Timber.d("TOR NOT SELECTED");
}
}
//HttpPost post = new HttpPost(getString(R.string.zt_request));
String urlWithAuth = getString(R.string.zt_request) + "?";
List<NameValuePair> params = new ArrayList<NameValuePair>();
for (String key : parameters.keySet()) {
//params.add(new BasicNameValuePair(key, parameters.get(key)));
urlWithAuth = urlWithAuth + URLEncoder.encode(key) + "=" + URLEncoder.encode(parameters.get(key)) + "&";
Timber.d("ADDING PARAMETER: " + key + ": " + parameters.get(key));
}
// drop trailing ampersand
urlWithAuth = urlWithAuth.substring(0, urlWithAuth.length() - 1);
Timber.d("CONSTRUCTED URL: " + urlWithAuth);
HttpPost post = new HttpPost(urlWithAuth);
/*
try {
post.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
} catch (UnsupportedEncodingException uee) {
Timber.e("FAILED TO ENCODE ENTITY");
uee.printStackTrace();
return null;
}
*/
HttpResponse response = null;
try {
response = client.execute(post);
} catch (ClientProtocolException cpe) {
Timber.e("FAILED TO EXECUTE REQUEST (CPE)");
cpe.printStackTrace();
return null;
} catch (IOException ioe) {
Timber.e("FAILED TO EXECUTE REQUEST (IOE)");
ioe.printStackTrace();
return null;
}
Timber.d("RESPONSE CODE: " + response.getStatusLine().getStatusCode());
StringBuffer result = new StringBuffer();
try {
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
String line = "";
while ((line = rd.readLine()) != null) {
result.append(line);
}
} catch (IOException ioe) {
Timber.e("FAILED TO READ RESPONSE");
ioe.printStackTrace();
return null;
}
Timber.d("RESPONSE: " + result.toString());
Header[] postHeaders = response.getAllHeaders();
for (int i = 0; i < postHeaders.length; i++) {
Timber.d("FOUND HEADER: " + postHeaders[i].getName() + ": " + postHeaders[i].getValue());
}
if (result.toString().contains("oauth_token=") && result.toString().contains("oauth_token_secret=")) {
String[] responseParts = result.toString().split("&");
String oauthToken = "";
String oauthTokenSecret = "";
for (String responsePart : responseParts) {
if (responsePart.contains("oauth_token=")) {
oauthToken = responsePart.substring(responsePart.indexOf("=") + 1);
}
if (responsePart.contains("oauth_token_secret=")) {
oauthTokenSecret = responsePart.substring(responsePart.indexOf("=") + 1);
}
}
mRequestToken = new Token(oauthToken, oauthTokenSecret, result.toString());
//
//mRequestToken = service.getRequestToken();
Timber.d("GOT REQUEST TOKEN: " + mRequestToken.getToken());
Timber.d("GETTING AUTH URL...");
String authorizationUrl = service.getAuthorizationUrl(mRequestToken);
// wp-api requires valid oauth callback url as well
try {
authorizationUrl = authorizationUrl + "&oauth_callback=" + URLEncoder.encode(getString(R.string.zt_callback), "UTF-8");
} catch (UnsupportedEncodingException uee) {
Timber.e("ENCODING CALLBACK FAILED");
uee.printStackTrace();
return null;
}
Timber.d("GOT AUTH URL: " + authorizationUrl);
return authorizationUrl;
//
} else {
Timber.e("TOKEN ELEMENTS MISSING FROM RESPONSE");
return null;
}
//
}
public void startZTWebActivity(String authorizationUrl) {
Timber.d("STARTING WEB ACTIVITY FOR " + authorizationUrl);
Intent i = new Intent(this, ZTWebActivity.class);
i.putExtra("authorizationUrl", authorizationUrl);
startActivityForResult(i, CODE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Timber.d("GOT ACTIVITY RESULT");
if (requestCode == CODE) {
if (resultCode == Activity.RESULT_OK) {
Bundle results = data.getExtras();
mAccessVerifier = new Verifier(results.getString("verifier"));
if ((mRequestToken != null) && (mAccessVerifier != null)) {
Timber.d("GOT TOKEN " + mRequestToken.getToken() + ", GOT VERIFIER " + mAccessVerifier.getValue());
VerifyTokenTask vtTask = new VerifyTokenTask(this);
vtTask.execute();
} else {
Timber.e("MISSING TOKEN AND/OR VERIFIER");
}
} else if (resultCode == Activity.RESULT_CANCELED) {
Timber.e("ACTIVITY CANCELLED");
} else {
Timber.e("UNEXPECTED RESULT");
}
} else {
Timber.e("UNEXPECTED REQUEST");
}
}
class VerifyTokenTask extends AsyncTask<String, String, String> {
private ZTLoginActivity ztla;
public VerifyTokenTask(ZTLoginActivity ztla) {
this.ztla = ztla;
}
@Override
protected String doInBackground(String... params) {
ztla.verifyToken();
return "foo";
}
protected void onPostExecute(String result) {
ztla.finish();
}
}
public void verifyToken() {
Timber.d("VERIFYING TOKEN...");
//
Map<String, String> parameters = service.getAccessParameters(mRequestToken, mAccessVerifier);
StrongHttpsClient client = getHttpClientInstance();
// check for tor
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
boolean useTor = settings.getBoolean("pusetor", false);
if (useTor) {
if ((!OrbotHelper.isOrbotInstalled(this)) || (!OrbotHelper.isOrbotRunning(this))) {
Timber.e("TOR SELECTED BUT ORBOT IS INACTIVE (ABORTING)");
return;
} else {
Timber.e("TOR SELECTED, HOST " + getString(R.string.zt_tor_host) + ", PORT " + getString(R.string.zt_tor_port) + " (SETTING PROXY)");
String host = getString(R.string.zt_tor_host);
int port = Integer.parseInt(getString(R.string.zt_tor_port));
HttpHost proxyHost = new HttpHost(host, port, "http");
client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxyHost);
proxySet = true;
// set proxy for scribe oauth service
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port));
service.setProxy(proxy);
}
} else {
if (proxySet) {
Timber.d("TOR NOT SELECTED (CLEARING PROXY)");
client.getParams().removeParameter(ConnRoutePNames.DEFAULT_PROXY);
proxySet = false;
// un-set proxy for scribe oauth service
service.setProxy(null);
} else {
Timber.d("TOR NOT SELECTED");
}
}
//HttpPost post = new HttpPost(getString(R.string.zt_access));
String urlWithAuth = getString(R.string.zt_access) + "?";
List<NameValuePair> params = new ArrayList<NameValuePair>();
for (String key : parameters.keySet()) {
//params.add(new BasicNameValuePair(key, parameters.get(key)));
urlWithAuth = urlWithAuth + URLEncoder.encode(key) + "=" + URLEncoder.encode(parameters.get(key)) + "&";
Timber.d("ADDING PARAMETER: " + key + ": " + parameters.get(key));
}
// drop trailing ampersand
urlWithAuth = urlWithAuth.substring(0, urlWithAuth.length() - 1);
Timber.d("CONSTRUCTED URL: " + urlWithAuth);
HttpPost post = new HttpPost(urlWithAuth);
/*
try {
post.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
} catch (UnsupportedEncodingException uee) {
Timber.e("FAILED TO ENCODE ENTITY");
uee.printStackTrace();
return;
}
*/
HttpResponse response = null;
try {
response = client.execute(post);
} catch (ClientProtocolException cpe) {
Timber.e("FAILED TO EXECUTE REQUEST (CPE)");
cpe.printStackTrace();
return;
} catch (IOException ioe) {
Timber.e("FAILED TO EXECUTE REQUEST (IOE)");
ioe.printStackTrace();
return;
}
Timber.d("RESPONSE CODE: " + response.getStatusLine().getStatusCode());
StringBuffer result = new StringBuffer();
try {
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
String line = "";
while ((line = rd.readLine()) != null) {
result.append(line);
}
} catch (IOException ioe) {
Timber.e("FAILED TO READ RESPONSE");
ioe.printStackTrace();
return;
}
Timber.d("RESPONSE: " + result.toString());
Header[] postHeaders = response.getAllHeaders();
for (int i = 0; i < postHeaders.length; i++) {
Timber.d("FOUND HEADER: " + postHeaders[i].getName() + ": " + postHeaders[i].getValue());
}
if (result.toString().contains("oauth_token=") && result.toString().contains("oauth_token_secret=")) {
String[] responseParts = result.toString().split("&");
String oauthToken = "";
String oauthTokenSecret = "";
for (String responsePart : responseParts) {
if (responsePart.contains("oauth_token=")) {
oauthToken = responsePart.substring(responsePart.indexOf("=") + 1);
}
if (responsePart.contains("oauth_token_secret=")) {
oauthTokenSecret = responsePart.substring(responsePart.indexOf("=") + 1);
}
}
mAccessToken = new Token(oauthToken, oauthTokenSecret, result.toString());
//
//mAccessToken = service.getAccessToken(mRequestToken, mAccessVerifier);
Timber.d("GOT ACCESS TOKEN: " + mAccessToken.getToken());
mAccessResult = RESULT_OK;
//
} else {
Timber.e("TOKEN ELEMENTS MISSING FROM RESPONSE");
}
//
return;
}
private synchronized StrongHttpsClient getHttpClientInstance() {
if (mClient == null) {
try {
mClient = new StrongHttpsClient(this, R.raw.debiancacerts, null);
//mClient = HttpClients.createDefault();
} catch (Exception e)
{
Log.e("NetCipher","error init'd stronghttpsclient",e);
}
}
return mClient;
}
@Override
public void finish() {
Intent data = new Intent();
if (mCacheWordHandler.isLocked()) {
Timber.d("cacheword was locked, no result to return from finish()");
} else {
// need complete credentials
String completeToken = mAccessToken.getToken() + "," + mAccessToken.getSecret();
data.putExtra(SiteController.EXTRAS_KEY_CREDENTIALS, completeToken);
}
setResult(mAccessResult, data);
// clear token to avoid confusion
mAccessToken = null;
super.finish();
}
}