diff options
Diffstat (limited to 'org.fox.ttrss/src/main/java/org/fox/ttrss/ApiCommon.java')
-rw-r--r-- | org.fox.ttrss/src/main/java/org/fox/ttrss/ApiCommon.java | 197 |
1 files changed, 150 insertions, 47 deletions
diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/ApiCommon.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/ApiCommon.java index b7308000..c75f6650 100644 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/ApiCommon.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/ApiCommon.java @@ -1,21 +1,42 @@ package org.fox.ttrss; -import android.os.Build; +import android.content.Context; +import android.content.SharedPreferences; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.preference.PreferenceManager; import android.util.Log; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSession; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; +import java.io.IOException; +import java.util.HashMap; + +import androidx.annotation.NonNull; +import okhttp3.Credentials; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; public class ApiCommon { public static final String TAG = "ApiCommon"; + private static final int API_STATUS_OK = 0; + private static final int API_STATUS_ERR = 1; + + private static final MediaType TYPE_JSON = MediaType.parse("application/json; charset=utf-8"); + + public interface ApiCaller { + void setStatusCode(int statusCode); + void setLastError(ApiError lastError); + void setLastErrorMessage(String message); + } + public enum ApiError { NO_ERROR, HTTP_UNAUTHORIZED, HTTP_FORBIDDEN, HTTP_NOT_FOUND, HTTP_SERVER_ERROR, HTTP_OTHER_ERROR, SSL_REJECTED, SSL_HOSTNAME_REJECTED, PARSE_ERROR, IO_ERROR, OTHER_ERROR, API_DISABLED, API_UNKNOWN, LOGIN_FAILED, INVALID_URL, API_INCORRECT_USAGE, NETWORK_UNAVAILABLE, API_UNKNOWN_METHOD } @@ -62,64 +83,146 @@ public class ApiCommon { Log.d(TAG, "getErrorMessage: unknown error code=" + error); return R.string.error_unknown; } + } + static boolean isNetworkAvailable(Context context) { + ConnectivityManager cm = (ConnectivityManager) + context.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo networkInfo = cm.getActiveNetworkInfo(); + + // if no network is available networkInfo will be null + // otherwise check if we are connected + return networkInfo != null && networkInfo.isConnected(); } - public static void trustAllHosts(boolean trustAnyCert, boolean trustAnyHost) { + static JsonElement performRequest(Context context, @NonNull HashMap<String, String> m_params, + @NonNull ApiCommon.ApiCaller caller) { try { - if (trustAnyCert) { - X509TrustManager easyTrustManager = new X509TrustManager() { + if (!ApiCommon.isNetworkAvailable(context)) { + caller.setLastError(ApiError.NETWORK_UNAVAILABLE); + return null; + } - public void checkClientTrusted( - X509Certificate[] chain, - String authType) throws CertificateException { - // Oh, I am easy! - } + SharedPreferences m_prefs = PreferenceManager.getDefaultSharedPreferences(context); - public void checkServerTrusted( - X509Certificate[] chain, - String authType) throws CertificateException { - // Oh, I am easy! - } + boolean m_transportDebugging = m_prefs.getBoolean("transport_debugging", false); - public X509Certificate[] getAcceptedIssuers() { - return null; - } + Gson gson = new Gson(); - }; + String payload = gson.toJson(new HashMap<>(m_params)); + String apiUrl = m_prefs.getString("ttrss_url", "").trim() + "/api/"; - // Create a trust manager that does not validate certificate chains - TrustManager[] trustAllCerts = new TrustManager[] {easyTrustManager}; + if (m_transportDebugging) Log.d(TAG, ">>> " + payload + " -> " + apiUrl); - // Install the all-trusting trust manager + Request.Builder requestBuilder = new Request.Builder() + .url(apiUrl) + .post(RequestBody.create(TYPE_JSON, payload)); - SSLContext sc = SSLContext.getInstance("TLS"); + String httpLogin = m_prefs.getString("http_login", "").trim(); + String httpPassword = m_prefs.getString("http_password", "").trim(); - sc.init(null, trustAllCerts, new java.security.SecureRandom()); + if (httpLogin.length() > 0) { + if (m_transportDebugging) Log.d(TAG, "Using HTTP Basic authentication."); - HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); + requestBuilder.addHeader("Authorization", Credentials.basic(httpLogin, httpPassword)); } - if (trustAnyHost) { - HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { - @Override - public boolean verify(String hostname, SSLSession session) { - return true; - } - }); + Request request = requestBuilder.build(); + + Response response = new OkHttpClient() + .newCall(request) + .execute(); + + if (response.isSuccessful()) { + String payloadReceived = response.body().string(); + + if (m_transportDebugging) Log.d(TAG, "<<< " + payloadReceived); + + JsonParser parser = new JsonParser(); + + JsonElement result = parser.parse(payloadReceived); + JsonObject resultObj = result.getAsJsonObject(); + + int statusCode = resultObj.get("status").getAsInt(); + + caller.setStatusCode(statusCode); + + switch (statusCode) { + case API_STATUS_OK: + return result.getAsJsonObject().get("content"); + case API_STATUS_ERR: + JsonObject contentObj = resultObj.get("content").getAsJsonObject(); + String error = contentObj.get("error").getAsString(); + + switch (error) { + case "LOGIN_ERROR": + case "NOT_LOGGED_IN": + caller.setLastError(ApiError.LOGIN_FAILED); + break; + case "API_DISABLED": + caller.setLastError(ApiError.API_DISABLED); + break; + case "INCORRECT_USAGE": + caller.setLastError(ApiError.API_INCORRECT_USAGE); + break; + case "UNKNOWN_METHOD": + caller.setLastError(ApiError.API_UNKNOWN_METHOD); + break; + default: + Log.d(TAG, "Unknown API error: " + error); + caller.setLastError(ApiError.API_UNKNOWN); + break; + } + } + + } else { + switch (response.code()) { + case 401: + caller.setLastError(ApiError.HTTP_UNAUTHORIZED); + break; + case 403: + caller.setLastError(ApiError.HTTP_FORBIDDEN); + break; + case 404: + caller.setLastError(ApiError.HTTP_NOT_FOUND); + break; + case 500: + case 501: + caller.setLastError(ApiError.HTTP_SERVER_ERROR); + break; + default: + Log.d(TAG, "HTTP response code: " + response.code()); + caller.setLastError(ApiError.HTTP_OTHER_ERROR); + break; + } } + return null; + } catch (javax.net.ssl.SSLPeerUnverifiedException e) { + caller.setLastError(ApiError.SSL_REJECTED); + caller.setLastErrorMessage(e.getMessage()); + e.printStackTrace(); + } catch (IOException e) { + caller.setLastError(ApiError.IO_ERROR); + caller.setLastErrorMessage(e.getMessage()); + + if (e.getMessage() != null) { + if (e.getMessage().matches("Hostname [^ ]+ was not verified")) { + caller.setLastError(ApiError.SSL_HOSTNAME_REJECTED); + } + } + + e.printStackTrace(); + } catch (com.google.gson.JsonSyntaxException e) { + caller.setLastError(ApiError.PARSE_ERROR); + caller.setLastErrorMessage(e.getMessage()); + e.printStackTrace(); } catch (Exception e) { + caller.setLastError(ApiError.OTHER_ERROR); + caller.setLastErrorMessage(e.getMessage()); e.printStackTrace(); } - } - @SuppressWarnings("deprecation") - protected 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"); - } + return null; } - } |