From 94b4aff15f4b7fe2b1a3380ac72e7637f9a7966a Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Tue, 18 Sep 2012 13:08:57 +0400 Subject: [PATCH] switch to HttpURLConnection (which should enable SNI on recent android versions) --- src/org/fox/ttrss/ApiRequest.java | 171 ++--- src/org/fox/ttrss/FeedsActivity.java | 3 + src/org/fox/ttrss/FeedsFragment.java | 113 ++-- .../offline/OfflineHeadlinesFragment.java | 2 +- src/org/fox/ttrss/util/Base64.java | 582 ------------------ .../ttrss/util/Base64DecoderException.java | 32 - .../fox/ttrss/util/EasySSLSocketFactory.java | 120 ---- .../fox/ttrss/util/EasyX509TrustManager.java | 26 - 8 files changed, 171 insertions(+), 878 deletions(-) delete mode 100644 src/org/fox/ttrss/util/Base64.java delete mode 100644 src/org/fox/ttrss/util/Base64DecoderException.java delete mode 100644 src/org/fox/ttrss/util/EasySSLSocketFactory.java delete mode 100644 src/org/fox/ttrss/util/EasyX509TrustManager.java diff --git a/src/org/fox/ttrss/ApiRequest.java b/src/org/fox/ttrss/ApiRequest.java index d067e394..ee510987 100644 --- a/src/org/fox/ttrss/ApiRequest.java +++ b/src/org/fox/ttrss/ApiRequest.java @@ -2,31 +2,27 @@ package org.fox.ttrss; import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStream; import java.io.InputStreamReader; -import java.net.MalformedURLException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; import java.net.URL; +import java.security.cert.CertificateException; import java.util.HashMap; -import org.apache.http.HttpHost; -import org.apache.http.HttpResponse; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.CredentialsProvider; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.protocol.ClientContext; -import org.apache.http.conn.scheme.Scheme; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.BasicCredentialsProvider; -import org.apache.http.protocol.BasicHttpContext; -import org.apache.http.protocol.HttpContext; -import org.fox.ttrss.util.EasySSLSocketFactory; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +import java.security.cert.X509Certificate; import android.content.Context; import android.content.SharedPreferences; -import android.net.http.AndroidHttpClient; import android.os.AsyncTask; +import android.os.Build; import android.preference.PreferenceManager; +import android.util.Base64; import android.util.Log; import com.google.gson.Gson; @@ -109,73 +105,61 @@ public class ApiRequest extends AsyncTask, Integer, JsonE Gson gson = new Gson(); String requestStr = gson.toJson(new HashMap(params[0])); + byte[] postData = null; + + try { + postData = requestStr.getBytes("UTF-8"); + } catch (UnsupportedEncodingException e) { + m_lastError = ApiError.OTHER_ERROR; + e.printStackTrace(); + return null; + } + + disableConnectionReuseIfNecessary(); if (m_transportDebugging) Log.d(TAG, ">>> (" + requestStr + ") " + m_api); - AndroidHttpClient client = AndroidHttpClient.newInstance("Tiny Tiny RSS"); + if (m_trustAny) trustAllHosts(); + + URL url; - if (m_trustAny) { - client.getConnectionManager().getSchemeRegistry().register(new Scheme("https", new EasySSLSocketFactory(), 443)); - } - try { - - HttpPost httpPost; - - try { - httpPost = new HttpPost(m_api + "/api/"); - } catch (IllegalArgumentException e) { - m_lastError = ApiError.INVALID_URL; - e.printStackTrace(); - client.close(); - return null; - } catch (Exception e) { - m_lastError = ApiError.OTHER_ERROR; - e.printStackTrace(); - client.close(); - return null; - } - - HttpContext context = null; - + url = new URL(m_api + "/api/"); + } catch (Exception e) { + m_lastError = ApiError.INVALID_URL; + e.printStackTrace(); + return null; + } + + try { + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + String httpLogin = m_prefs.getString("http_login", "").trim(); String httpPassword = m_prefs.getString("http_password", "").trim(); if (httpLogin.length() > 0) { if (m_transportDebugging) Log.d(TAG, "Using HTTP Basic authentication."); - - URL targetUrl; - try { - targetUrl = new URL(m_api); - } catch (MalformedURLException e) { - m_lastError = ApiError.INVALID_URL; - e.printStackTrace(); - client.close(); - return null; - } - HttpHost targetHost = new HttpHost(targetUrl.getHost(), targetUrl.getPort(), targetUrl.getProtocol()); - CredentialsProvider cp = new BasicCredentialsProvider(); - context = new BasicHttpContext(); - - cp.setCredentials( - new AuthScope(targetHost.getHostName(), targetHost.getPort()), - new UsernamePasswordCredentials(httpLogin, httpPassword)); - - context.setAttribute(ClientContext.CREDS_PROVIDER, cp); + conn.setRequestProperty("Authorization", "Basic " + + Base64.encode((httpLogin + ":" + httpPassword).getBytes("UTF-8"), Base64.NO_WRAP)); } - httpPost.setEntity(new StringEntity(requestStr, "utf-8")); - HttpResponse execute = client.execute(httpPost, context); - - m_httpStatusCode = execute.getStatusLine().getStatusCode(); + conn.setDoInput(true); + conn.setDoOutput(true); + conn.setUseCaches(false); + conn.setRequestMethod("POST"); + conn.setRequestProperty("Content-Length", Integer.toString(postData.length)); - switch (m_httpStatusCode) { + OutputStream out = conn.getOutputStream(); + out.write(postData); + out.close(); + + m_httpStatusCode = conn.getResponseCode(); + + switch (m_httpStatusCode) { case 200: - InputStream content = execute.getEntity().getContent(); - BufferedReader buffer = new BufferedReader( - new InputStreamReader(content), 8192); + new InputStreamReader(conn.getInputStream()), 8192); String s = ""; String response = ""; @@ -193,7 +177,7 @@ public class ApiRequest extends AsyncTask, Integer, JsonE m_apiStatusCode = resultObj.get("status").getAsInt(); - client.close(); + conn.disconnect(); switch (m_apiStatusCode) { case API_STATUS_OK: @@ -233,9 +217,9 @@ public class ApiRequest extends AsyncTask, Integer, JsonE m_lastError = ApiError.HTTP_OTHER_ERROR; break; } - - client.close(); - return null; + + conn.disconnect(); + return null; } catch (javax.net.ssl.SSLPeerUnverifiedException e) { m_lastError = ApiError.SSL_REJECTED; e.printStackTrace(); @@ -250,7 +234,50 @@ public class ApiRequest extends AsyncTask, Integer, JsonE e.printStackTrace(); } - client.close(); return null; } + + private static void trustAllHosts() { + X509TrustManager easyTrustManager = new X509TrustManager() { + + public void checkClientTrusted( + X509Certificate[] chain, + String authType) throws CertificateException { + // Oh, I am easy! + } + + public void checkServerTrusted( + X509Certificate[] chain, + String authType) throws CertificateException { + // Oh, I am easy! + } + + public X509Certificate[] getAcceptedIssuers() { + return null; + } + + }; + + // Create a trust manager that does not validate certificate chains + TrustManager[] trustAllCerts = new TrustManager[] {easyTrustManager}; + + // Install the all-trusting trust manager + try { + SSLContext sc = SSLContext.getInstance("TLS"); + + sc.init(null, trustAllCerts, new java.security.SecureRandom()); + + HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static void disableConnectionReuseIfNecessary() { + // HTTP connection reuse which was buggy pre-froyo + if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) { + System.setProperty("http.keepAlive", "false"); + } + } } diff --git a/src/org/fox/ttrss/FeedsActivity.java b/src/org/fox/ttrss/FeedsActivity.java index 302ce7a9..0d40da4a 100644 --- a/src/org/fox/ttrss/FeedsActivity.java +++ b/src/org/fox/ttrss/FeedsActivity.java @@ -6,6 +6,7 @@ import org.fox.ttrss.types.Article; import org.fox.ttrss.types.ArticleList; import org.fox.ttrss.types.Feed; import org.fox.ttrss.types.FeedCategory; +import org.fox.ttrss.util.AppRater; import android.content.Intent; import android.content.SharedPreferences; @@ -97,6 +98,8 @@ public class FeedsActivity extends OnlineActivity implements HeadlinesEventListe } ft.commit(); + + AppRater.appLaunched(this); } } } diff --git a/src/org/fox/ttrss/FeedsFragment.java b/src/org/fox/ttrss/FeedsFragment.java index 2e4a8433..7b307f84 100644 --- a/src/org/fox/ttrss/FeedsFragment.java +++ b/src/org/fox/ttrss/FeedsFragment.java @@ -5,29 +5,24 @@ import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.lang.reflect.Type; -import java.net.MalformedURLException; +import java.net.HttpURLConnection; import java.net.URL; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; -import org.apache.http.HttpHost; -import org.apache.http.HttpResponse; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.CredentialsProvider; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.protocol.ClientContext; -import org.apache.http.conn.scheme.Scheme; -import org.apache.http.impl.client.BasicCredentialsProvider; -import org.apache.http.protocol.BasicHttpContext; -import org.apache.http.protocol.HttpContext; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + import org.fox.ttrss.types.Feed; import org.fox.ttrss.types.FeedCategory; import org.fox.ttrss.types.FeedList; -import org.fox.ttrss.util.EasySSLSocketFactory; import android.app.Activity; import android.content.Context; @@ -37,10 +32,12 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.http.AndroidHttpClient; import android.os.AsyncTask; +import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.preference.PreferenceManager; import android.support.v4.app.Fragment; +import android.util.Base64; import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; @@ -541,46 +538,72 @@ public class FeedsFragment extends Fragment implements OnItemClickListener, OnSh return null; } + private void trustAllHosts() { + X509TrustManager easyTrustManager = new X509TrustManager() { + + public void checkClientTrusted( + X509Certificate[] chain, + String authType) throws CertificateException { + // Oh, I am easy! + } + + public void checkServerTrusted( + X509Certificate[] chain, + String authType) throws CertificateException { + // Oh, I am easy! + } + + public X509Certificate[] getAcceptedIssuers() { + return null; + } + + }; + + // Create a trust manager that does not validate certificate chains + TrustManager[] trustAllCerts = new TrustManager[] {easyTrustManager}; + + // Install the all-trusting trust manager + try { + SSLContext sc = SSLContext.getInstance("TLS"); + + sc.init(null, trustAllCerts, new java.security.SecureRandom()); + + HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void disableConnectionReuseIfNecessary() { + // HTTP connection reuse which was buggy pre-froyo + if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) { + System.setProperty("http.keepAlive", "false"); + } + } + protected void downloadFile(String fetchUrl, String outputFile) { AndroidHttpClient client = AndroidHttpClient.newInstance("Tiny Tiny RSS"); + disableConnectionReuseIfNecessary(); + if (m_prefs.getBoolean("ssl_trust_any", false)) { - client.getConnectionManager().getSchemeRegistry().register(new Scheme("https", new EasySSLSocketFactory(), 443)); + trustAllHosts(); } - HttpGet httpGet = new HttpGet(fetchUrl); - HttpContext context = null; - - String httpLogin = m_prefs.getString("http_login", ""); - String httpPassword = m_prefs.getString("http_password", ""); - - if (httpLogin.length() > 0) { - - URL targetUrl; - try { - targetUrl = new URL(fetchUrl); - } catch (MalformedURLException e) { - e.printStackTrace(); - client.close(); - return; - } - - HttpHost targetHost = new HttpHost(targetUrl.getHost(), targetUrl.getPort(), targetUrl.getProtocol()); - CredentialsProvider cp = new BasicCredentialsProvider(); - context = new BasicHttpContext(); - - cp.setCredentials( - new AuthScope(targetHost.getHostName(), targetHost.getPort()), - new UsernamePasswordCredentials(httpLogin, httpPassword)); - - context.setAttribute(ClientContext.CREDS_PROVIDER, cp); - } - - try { - HttpResponse execute = client.execute(httpGet, context); + URL url = new URL(fetchUrl); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + + String httpLogin = m_prefs.getString("http_login", ""); + String httpPassword = m_prefs.getString("http_password", ""); - InputStream content = execute.getEntity().getContent(); + if (httpLogin.length() > 0) { + conn.setRequestProperty("Authorization", "Basic " + + Base64.encode((httpLogin + ":" + httpPassword).getBytes("UTF-8"), Base64.NO_WRAP)); + } + + InputStream content = conn.getInputStream(); BufferedInputStream is = new BufferedInputStream(content, 1024); FileOutputStream fos = new FileOutputStream(outputFile); diff --git a/src/org/fox/ttrss/offline/OfflineHeadlinesFragment.java b/src/org/fox/ttrss/offline/OfflineHeadlinesFragment.java index 769a3795..0a4c416b 100644 --- a/src/org/fox/ttrss/offline/OfflineHeadlinesFragment.java +++ b/src/org/fox/ttrss/offline/OfflineHeadlinesFragment.java @@ -467,7 +467,7 @@ public class OfflineHeadlinesFragment extends Fragment implements OnItemClickLis if (feedTitle.length() > 20) feedTitle = feedTitle.substring(0, 20) + "..."; - if (feedTitle != null) { + if (feedTitle.length() > 0) { ft.setText(feedTitle); } else { ft.setVisibility(View.GONE); diff --git a/src/org/fox/ttrss/util/Base64.java b/src/org/fox/ttrss/util/Base64.java deleted file mode 100644 index 5c8136db..00000000 --- a/src/org/fox/ttrss/util/Base64.java +++ /dev/null @@ -1,582 +0,0 @@ -// Portions copyright 2002, Google, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -package org.fox.ttrss.util; - -// This code was converted from code at http://iharder.sourceforge.net/base64/ -// Lots of extraneous features were removed. -/* The original code said: - *

- * I am placing this code in the Public Domain. Do with it as you will. - * This software comes with no guarantees or warranties but with - * plenty of well-wishing instead! - * Please visit - * http://iharder.net/xmlizable - * periodically to check for updates or to contribute improvements. - *

- * - * @author Robert Harder - * @author rharder@usa.net - * @version 1.3 - */ - -/** - * Base64 converter class. This code is not a complete MIME encoder; it simply - * converts binary data to base64 data and back. - * - *

- * Note {@link CharBase64} is a GWT-compatible implementation of this class. - */ -public class Base64 { - /** Specify encoding (value is {@code true}). */ - public final static boolean ENCODE = true; - - /** Specify decoding (value is {@code false}). */ - public final static boolean DECODE = false; - - /** The equals sign (=) as a byte. */ - private final static byte EQUALS_SIGN = (byte) '='; - - /** The new line character (\n) as a byte. */ - private final static byte NEW_LINE = (byte) '\n'; - - /** - * The 64 valid Base64 values. - */ - private final static byte[] ALPHABET = { (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G', - (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', (byte) 'Q', - (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) 'a', - (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', - (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u', - (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', - (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) '+', (byte) '/' }; - - /** - * The 64 valid web safe Base64 values. - */ - private final static byte[] WEBSAFE_ALPHABET = { (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G', - (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', (byte) 'Q', - (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) 'a', - (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', - (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u', - (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', - (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) '-', (byte) '_' }; - - /** - * Translates a Base64 value to either its 6-bit reconstruction value or a - * negative number indicating some other meaning. - **/ - private final static byte[] DECODABET = { -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal - // 0 - // - - // 8 - -5, -5, // Whitespace: Tab and Linefeed - -9, -9, // Decimal 11 - 12 - -5, // Whitespace: Carriage Return - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - - // 26 - -9, -9, -9, -9, -9, // Decimal 27 - 31 - -5, // Whitespace: Space - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42 - 62, // Plus sign at decimal 43 - -9, -9, -9, // Decimal 44 - 46 - 63, // Slash at decimal 47 - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine - -9, -9, -9, // Decimal 58 - 60 - -1, // Equals sign at decimal 61 - -9, -9, -9, // Decimal 62 - 64 - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through - // 'N' - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' - // through 'Z' - -9, -9, -9, -9, -9, -9, // Decimal 91 - 96 - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' - // through 'm' - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' - // through 'z' - -9, -9, -9, -9, -9 // Decimal 123 - 127 - /* - * ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139 - * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 - * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 - * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 - * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 - * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 - * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 - * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 - * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 - * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 - */ - }; - - /** The web safe decodabet */ - private final static byte[] WEBSAFE_DECODABET = { -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal - // 0 - // - - // 8 - -5, -5, // Whitespace: Tab and Linefeed - -9, -9, // Decimal 11 - 12 - -5, // Whitespace: Carriage Return - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - - // 26 - -9, -9, -9, -9, -9, // Decimal 27 - 31 - -5, // Whitespace: Space - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 44 - 62, // Dash '-' sign at decimal 45 - -9, -9, // Decimal 46-47 - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine - -9, -9, -9, // Decimal 58 - 60 - -1, // Equals sign at decimal 61 - -9, -9, -9, // Decimal 62 - 64 - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through - // 'N' - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' - // through 'Z' - -9, -9, -9, -9, // Decimal 91-94 - 63, // Underscore '_' at decimal 95 - -9, // Decimal 96 - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' - // through 'm' - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' - // through 'z' - -9, -9, -9, -9, -9 // Decimal 123 - 127 - /* - * ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139 - * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 - * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 - * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 - * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 - * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 - * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 - * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 - * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 - * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 - */ - }; - - // Indicates white space in encoding - private final static byte WHITE_SPACE_ENC = -5; - // Indicates equals sign in encoding - private final static byte EQUALS_SIGN_ENC = -1; - - /** Defeats instantiation. */ - private Base64() { - } - - /* ******** E N C O D I N G M E T H O D S ******** */ - - /** - * Encodes up to three bytes of the array source and writes the - * resulting four Base64 bytes to destination. The source and - * destination arrays can be manipulated anywhere along their length by - * specifying srcOffset and destOffset. This method - * does not check to make sure your arrays are large enough to accommodate - * srcOffset + 3 for the source array or - * destOffset + 4 for the destination array. The - * actual number of significant bytes in your array is given by - * numSigBytes. - * - * @param source - * the array to convert - * @param srcOffset - * the index where conversion begins - * @param numSigBytes - * the number of significant bytes in your array - * @param destination - * the array to hold the conversion - * @param destOffset - * the index where output will be put - * @param alphabet - * is the encoding alphabet - * @return the destination array - * @since 1.3 - */ - private static byte[] encode3to4(byte[] source, int srcOffset, int numSigBytes, byte[] destination, int destOffset, byte[] alphabet) { - // 1 2 3 - // 01234567890123456789012345678901 Bit position - // --------000000001111111122222222 Array position from threeBytes - // --------| || || || | Six bit groups to index alphabet - // >>18 >>12 >> 6 >> 0 Right shift necessary - // 0x3f 0x3f 0x3f Additional AND - - // Create buffer with zero-padding if there are only one or two - // significant bytes passed in the array. - // We have to shift left 24 in order to flush out the 1's that appear - // when Java treats a value as negative that is cast from a byte to an - // int. - int inBuff = (numSigBytes > 0 ? ((source[srcOffset] << 24) >>> 8) : 0) - | (numSigBytes > 1 ? ((source[srcOffset + 1] << 24) >>> 16) : 0) - | (numSigBytes > 2 ? ((source[srcOffset + 2] << 24) >>> 24) : 0); - - switch (numSigBytes) { - case 3: - destination[destOffset] = alphabet[(inBuff >>> 18)]; - destination[destOffset + 1] = alphabet[(inBuff >>> 12) & 0x3f]; - destination[destOffset + 2] = alphabet[(inBuff >>> 6) & 0x3f]; - destination[destOffset + 3] = alphabet[(inBuff) & 0x3f]; - return destination; - case 2: - destination[destOffset] = alphabet[(inBuff >>> 18)]; - destination[destOffset + 1] = alphabet[(inBuff >>> 12) & 0x3f]; - destination[destOffset + 2] = alphabet[(inBuff >>> 6) & 0x3f]; - destination[destOffset + 3] = EQUALS_SIGN; - return destination; - case 1: - destination[destOffset] = alphabet[(inBuff >>> 18)]; - destination[destOffset + 1] = alphabet[(inBuff >>> 12) & 0x3f]; - destination[destOffset + 2] = EQUALS_SIGN; - destination[destOffset + 3] = EQUALS_SIGN; - return destination; - default: - return destination; - } // end switch - } // end encode3to4 - - /** - * Encodes a byte array into Base64 notation. Equivalent to calling {@code - * encodeBytes(source, 0, source.length)} - * - * @param source - * The data to convert - * @since 1.4 - */ - public static String encode(byte[] source) { - return encode(source, 0, source.length, ALPHABET, true); - } - - /** - * Encodes a byte array into web safe Base64 notation. - * - * @param source - * The data to convert - * @param doPadding - * is {@code true} to pad result with '=' chars if it does not - * fall on 3 byte boundaries - */ - public static String encodeWebSafe(byte[] source, boolean doPadding) { - return encode(source, 0, source.length, WEBSAFE_ALPHABET, doPadding); - } - - /** - * Encodes a byte array into Base64 notation. - * - * @param source - * the data to convert - * @param off - * offset in array where conversion should begin - * @param len - * length of data to convert - * @param alphabet - * the encoding alphabet - * @param doPadding - * is {@code true} to pad result with '=' chars if it does not - * fall on 3 byte boundaries - * @since 1.4 - */ - public static String encode(byte[] source, int off, int len, byte[] alphabet, boolean doPadding) { - byte[] outBuff = encode(source, off, len, alphabet, Integer.MAX_VALUE); - int outLen = outBuff.length; - - // If doPadding is false, set length to truncate '=' - // padding characters - while (doPadding == false && outLen > 0) { - if (outBuff[outLen - 1] != '=') { - break; - } - outLen -= 1; - } - - return new String(outBuff, 0, outLen); - } - - /** - * Encodes a byte array into Base64 notation. - * - * @param source - * the data to convert - * @param off - * offset in array where conversion should begin - * @param len - * length of data to convert - * @param alphabet - * is the encoding alphabet - * @param maxLineLength - * maximum length of one line. - * @return the BASE64-encoded byte array - */ - public static byte[] encode(byte[] source, int off, int len, byte[] alphabet, int maxLineLength) { - int lenDiv3 = (len + 2) / 3; // ceil(len / 3) - int len43 = lenDiv3 * 4; - byte[] outBuff = new byte[len43 // Main 4:3 - + (len43 / maxLineLength)]; // New lines - - int d = 0; - int e = 0; - int len2 = len - 2; - int lineLength = 0; - for (; d < len2; d += 3, e += 4) { - - // The following block of code is the same as - // encode3to4( source, d + off, 3, outBuff, e, alphabet ); - // but inlined for faster encoding (~20% improvement) - int inBuff = ((source[d + off] << 24) >>> 8) | ((source[d + 1 + off] << 24) >>> 16) | ((source[d + 2 + off] << 24) >>> 24); - outBuff[e] = alphabet[(inBuff >>> 18)]; - outBuff[e + 1] = alphabet[(inBuff >>> 12) & 0x3f]; - outBuff[e + 2] = alphabet[(inBuff >>> 6) & 0x3f]; - outBuff[e + 3] = alphabet[(inBuff) & 0x3f]; - - lineLength += 4; - if (lineLength == maxLineLength) { - outBuff[e + 4] = NEW_LINE; - e++; - lineLength = 0; - } // end if: end of line - } // end for: each piece of array - - if (d < len) { - encode3to4(source, d + off, len - d, outBuff, e, alphabet); - - lineLength += 4; - if (lineLength == maxLineLength) { - // Add a last newline - outBuff[e + 4] = NEW_LINE; - e++; - } - e += 4; - } - - assert (e == outBuff.length); - return outBuff; - } - - /* ******** D E C O D I N G M E T H O D S ******** */ - - /** - * Decodes four bytes from array source and writes the resulting - * bytes (up to three of them) to destination. The source and - * destination arrays can be manipulated anywhere along their length by - * specifying srcOffset and destOffset. This method - * does not check to make sure your arrays are large enough to accommodate - * srcOffset + 4 for the source array or - * destOffset + 3 for the destination array. This - * method returns the actual number of bytes that were converted from the - * Base64 encoding. - * - * - * @param source - * the array to convert - * @param srcOffset - * the index where conversion begins - * @param destination - * the array to hold the conversion - * @param destOffset - * the index where output will be put - * @param decodabet - * the decodabet for decoding Base64 content - * @return the number of decoded bytes converted - * @since 1.3 - */ - private static int decode4to3(byte[] source, int srcOffset, byte[] destination, int destOffset, byte[] decodabet) { - // Example: Dk== - if (source[srcOffset + 2] == EQUALS_SIGN) { - int outBuff = ((decodabet[source[srcOffset]] << 24) >>> 6) | ((decodabet[source[srcOffset + 1]] << 24) >>> 12); - - destination[destOffset] = (byte) (outBuff >>> 16); - return 1; - } else if (source[srcOffset + 3] == EQUALS_SIGN) { - // Example: DkL= - int outBuff = ((decodabet[source[srcOffset]] << 24) >>> 6) | ((decodabet[source[srcOffset + 1]] << 24) >>> 12) - | ((decodabet[source[srcOffset + 2]] << 24) >>> 18); - - destination[destOffset] = (byte) (outBuff >>> 16); - destination[destOffset + 1] = (byte) (outBuff >>> 8); - return 2; - } else { - // Example: DkLE - int outBuff = ((decodabet[source[srcOffset]] << 24) >>> 6) | ((decodabet[source[srcOffset + 1]] << 24) >>> 12) - | ((decodabet[source[srcOffset + 2]] << 24) >>> 18) | ((decodabet[source[srcOffset + 3]] << 24) >>> 24); - - destination[destOffset] = (byte) (outBuff >> 16); - destination[destOffset + 1] = (byte) (outBuff >> 8); - destination[destOffset + 2] = (byte) (outBuff); - return 3; - } - } // end decodeToBytes - - /** - * Decodes data from Base64 notation. - * - * @param s - * the string to decode (decoded in default encoding) - * @return the decoded data - * @since 1.4 - */ - public static byte[] decode(String s) throws Base64DecoderException { - byte[] bytes = s.getBytes(); - return decode(bytes, 0, bytes.length); - } - - /** - * Decodes data from web safe Base64 notation. Web safe encoding uses '-' - * instead of '+', '_' instead of '/' - * - * @param s - * the string to decode (decoded in default encoding) - * @return the decoded data - */ - public static byte[] decodeWebSafe(String s) throws Base64DecoderException { - byte[] bytes = s.getBytes(); - return decodeWebSafe(bytes, 0, bytes.length); - } - - /** - * Decodes Base64 content in byte array format and returns the decoded byte - * array. - * - * @param source - * The Base64 encoded data - * @return decoded data - * @since 1.3 - * @throws Base64DecoderException - */ - public static byte[] decode(byte[] source) throws Base64DecoderException { - return decode(source, 0, source.length); - } - - /** - * Decodes web safe Base64 content in byte array format and returns the - * decoded data. Web safe encoding uses '-' instead of '+', '_' instead of - * '/' - * - * @param source - * the string to decode (decoded in default encoding) - * @return the decoded data - */ - public static byte[] decodeWebSafe(byte[] source) throws Base64DecoderException { - return decodeWebSafe(source, 0, source.length); - } - - /** - * Decodes Base64 content in byte array format and returns the decoded byte - * array. - * - * @param source - * the Base64 encoded data - * @param off - * the offset of where to begin decoding - * @param len - * the length of characters to decode - * @return decoded data - * @since 1.3 - * @throws Base64DecoderException - */ - public static byte[] decode(byte[] source, int off, int len) throws Base64DecoderException { - return decode(source, off, len, DECODABET); - } - - /** - * Decodes web safe Base64 content in byte array format and returns the - * decoded byte array. Web safe encoding uses '-' instead of '+', '_' - * instead of '/' - * - * @param source - * the Base64 encoded data - * @param off - * the offset of where to begin decoding - * @param len - * the length of characters to decode - * @return decoded data - */ - public static byte[] decodeWebSafe(byte[] source, int off, int len) throws Base64DecoderException { - return decode(source, off, len, WEBSAFE_DECODABET); - } - - /** - * Decodes Base64 content using the supplied decodabet and returns the - * decoded byte array. - * - * @param source - * the Base64 encoded data - * @param off - * the offset of where to begin decoding - * @param len - * the length of characters to decode - * @param decodabet - * the decodabet for decoding Base64 content - * @return decoded data - */ - public static byte[] decode(byte[] source, int off, int len, byte[] decodabet) throws Base64DecoderException { - int len34 = len * 3 / 4; - byte[] outBuff = new byte[2 + len34]; // Upper limit on size of output - int outBuffPosn = 0; - - byte[] b4 = new byte[4]; - int b4Posn = 0; - int i = 0; - byte sbiCrop = 0; - byte sbiDecode = 0; - for (i = 0; i < len; i++) { - sbiCrop = (byte) (source[i + off] & 0x7f); // Only the low seven - // bits - sbiDecode = decodabet[sbiCrop]; - - if (sbiDecode >= WHITE_SPACE_ENC) { // White space Equals sign or - // better - if (sbiDecode >= EQUALS_SIGN_ENC) { - // An equals sign (for padding) must not occur at position 0 - // or 1 - // and must be the last byte[s] in the encoded value - if (sbiCrop == EQUALS_SIGN) { - int bytesLeft = len - i; - byte lastByte = (byte) (source[len - 1 + off] & 0x7f); - if (b4Posn == 0 || b4Posn == 1) { - throw new Base64DecoderException("invalid padding byte '=' at byte offset " + i); - } else if ((b4Posn == 3 && bytesLeft > 2) || (b4Posn == 4 && bytesLeft > 1)) { - throw new Base64DecoderException("padding byte '=' falsely signals end of encoded value " + "at offset " + i); - } else if (lastByte != EQUALS_SIGN && lastByte != NEW_LINE) { - throw new Base64DecoderException("encoded value has invalid trailing byte"); - } - break; - } - - b4[b4Posn++] = sbiCrop; - if (b4Posn == 4) { - outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn, decodabet); - b4Posn = 0; - } - } - } else { - throw new Base64DecoderException("Bad Base64 input character at " + i + ": " + source[i + off] + "(decimal)"); - } - } - - // Because web safe encoding allows non padding base64 encodes, we - // need to pad the rest of the b4 buffer with equal signs when - // b4Posn != 0. There can be at most 2 equal signs at the end of - // four characters, so the b4 buffer must have two or three - // characters. This also catches the case where the input is - // padded with EQUALS_SIGN - if (b4Posn != 0) { - if (b4Posn == 1) { - // Ensure you have set your public key - throw new Base64DecoderException("single trailing character at offset " + (len - 1)); - } - b4[b4Posn++] = EQUALS_SIGN; - outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn, decodabet); - } - - byte[] out = new byte[outBuffPosn]; - System.arraycopy(outBuff, 0, out, 0, outBuffPosn); - return out; - } -} diff --git a/src/org/fox/ttrss/util/Base64DecoderException.java b/src/org/fox/ttrss/util/Base64DecoderException.java deleted file mode 100644 index 7b7be229..00000000 --- a/src/org/fox/ttrss/util/Base64DecoderException.java +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2002, Google, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package org.fox.ttrss.util;; - -/** - * Exception thrown when encountering an invalid Base64 input character. - * - * @author nelson - */ -public class Base64DecoderException extends Exception { - public Base64DecoderException() { - super(); - } - - public Base64DecoderException(String s) { - super(s); - } - - private static final long serialVersionUID = 1L; -} diff --git a/src/org/fox/ttrss/util/EasySSLSocketFactory.java b/src/org/fox/ttrss/util/EasySSLSocketFactory.java deleted file mode 100644 index f0c2d3ad..00000000 --- a/src/org/fox/ttrss/util/EasySSLSocketFactory.java +++ /dev/null @@ -1,120 +0,0 @@ -package org.fox.ttrss.util; - -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/util/EasyX509TrustManager.java b/src/org/fox/ttrss/util/EasyX509TrustManager.java deleted file mode 100644 index 5ffc19bb..00000000 --- a/src/org/fox/ttrss/util/EasyX509TrustManager.java +++ /dev/null @@ -1,26 +0,0 @@ - -package org.fox.ttrss.util; - -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]; - } - -}