diff --git a/res/values/strings.xml b/res/values/strings.xml index c190ac3a..7c7408fb 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -21,6 +21,7 @@ Preferences Light Login failed: API disabled. + Login failed: no data received. Login failed: username or password incorrect. Logged in. No unread feeds. @@ -36,4 +37,5 @@ Load more... Show all articles Show unread articles + Accept any SSL certificate diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml index 10cb3cca..1c102fb0 100644 --- a/res/xml/preferences.xml +++ b/res/xml/preferences.xml @@ -8,7 +8,7 @@ - + diff --git a/src/org/fox/ttrss/ApiRequest.java b/src/org/fox/ttrss/ApiRequest.java index 5678b1fc..f2cdecdc 100644 --- a/src/org/fox/ttrss/ApiRequest.java +++ b/src/org/fox/ttrss/ApiRequest.java @@ -7,8 +7,14 @@ import java.util.HashMap; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpPost; +import org.apache.http.conn.scheme.PlainSocketFactory; +import org.apache.http.conn.scheme.Scheme; +import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; +import org.apache.http.params.BasicHttpParams; +import org.apache.http.params.HttpParams; import android.os.AsyncTask; import android.util.Log; @@ -26,11 +32,16 @@ public class ApiRequest extends AsyncTask, Integer, JsonE protected static final int STATUS_OTHER_ERROR = 3; private String m_api; + private boolean m_trustAny = false; protected void setApi(String api) { m_api = api; } + public void setTrustAny(boolean trust) { + m_trustAny = trust; + } + @Override protected JsonElement doInBackground(HashMap... params) { @@ -38,9 +49,22 @@ public class ApiRequest extends AsyncTask, Integer, JsonE String requestStr = gson.toJson(new HashMap(params[0])); - Log.d(TAG, ">>> (" + requestStr + ") " + m_api); + //Log.d(TAG, ">>> (" + requestStr + ") " + m_api); - DefaultHttpClient client = new DefaultHttpClient(); + DefaultHttpClient client; + + if (m_trustAny) { + SchemeRegistry schemeRegistry = new SchemeRegistry(); + schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); + schemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(), 443)); + + HttpParams httpParams = new BasicHttpParams(); + + client = new DefaultHttpClient(new ThreadSafeClientConnManager(httpParams, schemeRegistry), httpParams); + } else { + client = new DefaultHttpClient(); + } + HttpPost httpPost = new HttpPost(m_api + "/api/"); try { @@ -68,6 +92,7 @@ public class ApiRequest extends AsyncTask, Integer, JsonE } catch (Exception e) { e.printStackTrace(); } + return null; } diff --git a/src/org/fox/ttrss/EasySSLSocketFactory.java b/src/org/fox/ttrss/EasySSLSocketFactory.java new file mode 100644 index 00000000..2bb6ea14 --- /dev/null +++ b/src/org/fox/ttrss/EasySSLSocketFactory.java @@ -0,0 +1,120 @@ +package org.fox.ttrss; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.UnknownHostException; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.TrustManager; + +import org.apache.http.conn.ConnectTimeoutException; +import org.apache.http.conn.scheme.LayeredSocketFactory; +import org.apache.http.conn.scheme.SocketFactory; +import org.apache.http.params.HttpConnectionParams; +import org.apache.http.params.HttpParams; + +public class EasySSLSocketFactory implements SocketFactory, LayeredSocketFactory +{ + private SSLContext sslcontext = null; + + private static SSLContext createEasySSLContext() throws IOException + { + try + { + SSLContext context = SSLContext.getInstance("TLS"); + context.init(null, new TrustManager[] { new EasyX509TrustManager() }, null); + return context; + } + catch (Exception e) + { + throw new IOException(e.getMessage()); + } + } + + private SSLContext getSSLContext() throws IOException + { + if (this.sslcontext == null) + { + this.sslcontext = createEasySSLContext(); + } + return this.sslcontext; + } + + /** + * @see org.apache.http.conn.scheme.SocketFactory#connectSocket(java.net.Socket, java.lang.String, int, + * java.net.InetAddress, int, org.apache.http.params.HttpParams) + */ + public Socket connectSocket(Socket sock, + String host, + int port, + InetAddress localAddress, + int localPort, + HttpParams params) + + throws IOException, UnknownHostException, ConnectTimeoutException + { + int connTimeout = HttpConnectionParams.getConnectionTimeout(params); + int soTimeout = HttpConnectionParams.getSoTimeout(params); + InetSocketAddress remoteAddress = new InetSocketAddress(host, port); + SSLSocket sslsock = (SSLSocket) ((sock != null) ? sock : createSocket()); + + if ((localAddress != null) || (localPort > 0)) + { + // we need to bind explicitly + if (localPort < 0) + { + localPort = 0; // indicates "any" + } + InetSocketAddress isa = new InetSocketAddress(localAddress, localPort); + sslsock.bind(isa); + } + + sslsock.connect(remoteAddress, connTimeout); + sslsock.setSoTimeout(soTimeout); + return sslsock; + } + + /** + * @see org.apache.http.conn.scheme.SocketFactory#createSocket() + */ + public Socket createSocket() throws IOException { + return getSSLContext().getSocketFactory().createSocket(); + } + + /** + * @see org.apache.http.conn.scheme.SocketFactory#isSecure(java.net.Socket) + */ + public boolean isSecure(Socket socket) throws IllegalArgumentException { + return true; + } + + /** + * @see org.apache.http.conn.scheme.LayeredSocketFactory#createSocket(java.net.Socket, java.lang.String, int, + * boolean) + */ + public Socket createSocket(Socket socket, + String host, + int port, + boolean autoClose) throws IOException, + UnknownHostException + { + return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose); + } + + // ------------------------------------------------------------------- + // javadoc in org.apache.http.conn.scheme.SocketFactory says : + // Both Object.equals() and Object.hashCode() must be overridden + // for the correct operation of some connection managers + // ------------------------------------------------------------------- + + public boolean equals(Object obj) { + return ((obj != null) && obj.getClass().equals(EasySSLSocketFactory.class)); + } + + public int hashCode() { + return EasySSLSocketFactory.class.hashCode(); + } +} \ No newline at end of file diff --git a/src/org/fox/ttrss/EasyX509TrustManager.java b/src/org/fox/ttrss/EasyX509TrustManager.java new file mode 100644 index 00000000..6842a1a6 --- /dev/null +++ b/src/org/fox/ttrss/EasyX509TrustManager.java @@ -0,0 +1,26 @@ + +package org.fox.ttrss; + +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import javax.net.ssl.X509TrustManager; + +// http://stackoverflow.com/questions/6989116/httpget-not-working-due-to-not-trusted-server-certificate-but-it-works-with-ht + +public class EasyX509TrustManager implements X509TrustManager { + + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) + throws CertificateException { } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) + throws CertificateException { } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + +} diff --git a/src/org/fox/ttrss/FeedsFragment.java b/src/org/fox/ttrss/FeedsFragment.java index d4480dba..df7ef6be 100644 --- a/src/org/fox/ttrss/FeedsFragment.java +++ b/src/org/fox/ttrss/FeedsFragment.java @@ -133,6 +133,7 @@ public class FeedsFragment extends Fragment implements OnItemClickListener { FeedsRequest fr = new FeedsRequest(); fr.setApi(m_prefs.getString("ttrss_url", null)); + fr.setTrustAny(m_prefs.getBoolean("ssl_trust_any", false)); final String sessionId = ((MainActivity)getActivity()).getSessionId(); final boolean unreadOnly = ((MainActivity)getActivity()).getUnreadOnly(); @@ -212,8 +213,9 @@ public class FeedsFragment extends Fragment implements OnItemClickListener { // report null object received } + showLoading(false); + return; - } } diff --git a/src/org/fox/ttrss/HeadlinesFragment.java b/src/org/fox/ttrss/HeadlinesFragment.java index f6920b5e..734c21a4 100644 --- a/src/org/fox/ttrss/HeadlinesFragment.java +++ b/src/org/fox/ttrss/HeadlinesFragment.java @@ -125,6 +125,7 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener { HeadlinesRequest req = new HeadlinesRequest(); req.setApi(m_prefs.getString("ttrss_url", null)); + req.setTrustAny(m_prefs.getBoolean("ssl_trust_any", false)); final String sessionId = ((MainActivity)getActivity()).getSessionId(); final boolean showUnread = ((MainActivity)getActivity()).getUnreadArticlesOnly(); @@ -226,6 +227,8 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener { // report null object } + showLoading(false); + return; } diff --git a/src/org/fox/ttrss/MainActivity.java b/src/org/fox/ttrss/MainActivity.java index fb16a3d3..9f5b88f8 100644 --- a/src/org/fox/ttrss/MainActivity.java +++ b/src/org/fox/ttrss/MainActivity.java @@ -490,8 +490,10 @@ public class MainActivity extends FragmentActivity implements FeedsFragment.OnFe } catch (Exception e) { e.printStackTrace(); } + } else { + setLoadingStatus(R.string.login_no_data, false); } - } + } } @Override @@ -601,7 +603,8 @@ public class MainActivity extends FragmentActivity implements FeedsFragment.OnFe LoginRequest ar = new LoginRequest(); ar.setApi(m_prefs.getString("ttrss_url", null)); - + ar.setTrustAny(m_prefs.getBoolean("ssl_trust_any", false)); + HashMap map = new HashMap() { { put("op", "login");