online.privacy.PrivacyOnlineApiRequest.java Source code

Java tutorial

Introduction

Here is the source code for online.privacy.PrivacyOnlineApiRequest.java

Source

package online.privacy;

/**
 * HTTPS API communication class.
 *
 * Talks to the Privacy Online API over HTTPS using JSON payloads.
 * Used to verify user credentials and obtain available VPN location node lists.
 *
 * Copyright  2016, privacy.online
 * All rights reserved.
 *
 * This file is part of Privacy Online for Android.
 *
 * Privacy Online for Android is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Privacy Online for Android is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Privacy Online for Android.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @author James Ronan <jim@dev.uk2.net>
 */
import android.content.Context;
import android.util.Log;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;

import javax.net.ssl.HttpsURLConnection;

public class PrivacyOnlineApiRequest {

    private static final String LOG_TAG = "p.o.api.request";
    private Context context;

    public static final int VERIFY_FAIL = 0;
    public static final int VERIFY_OK = 1;
    public static final int VERIFY_ERROR = 2;

    PrivacyOnlineApiRequest(Context context) {
        this.context = context;
    }

    /**
     * Uses HTTPS to verify the supplied credentials against the Privacy Online user account
     * API. Returns true/false indicating whether or not the supplied credentials are valid.
     *
     * @param  username Username for account.
     * @param  password Password for account.
     * @return int Validity of account credentials.
     */
    public int verifyUserAccount(String username, String password) {

        JSONObject responseData;
        try {
            JSONObject requestData = new JSONObject();
            requestData.put("username", username);
            requestData.put("password", password);
            responseData = makeAPIRequest("PUT", "/user/verify", requestData.toString());
            Log.e(LOG_TAG, responseData.toString());

            if (responseData.has("success")) {
                return VERIFY_OK;

            } else if (responseData.has("error")) {
                JSONObject errorObject = responseData.getJSONObject("error");
                if (errorObject.has("authentication")) {
                    JSONObject authenticationError = errorObject.getJSONObject("authentication");
                    if (authenticationError.has("user")) {
                        return VERIFY_FAIL;
                    }
                }

                return VERIFY_ERROR;
            }

        } catch (JSONException je) {
            Log.e(LOG_TAG, je.toString());
            return VERIFY_ERROR;

        } catch (IOException ioe) {
            Log.e(LOG_TAG, ioe.toString());
            return VERIFY_ERROR;
        }

        return VERIFY_ERROR;
    }

    /**
     * Retrieves a list of the currently available VPN locations from the Privacy Online API.
     *
     * *Not Currently Used*
     * TODO - update the error handling when this is eventually used.
     *
     * @return ArrayList of VPNLocations
     */
    public ArrayList<VPNLocation> getLocationList() {
        JSONObject responseData;
        ArrayList<VPNLocation> locationList;
        try {
            responseData = makeAPIRequest("GET", "/location", "");
            JSONArray locations = responseData.getJSONArray("location");
            locationList = new ArrayList<>(locations.length());
            for (int i = 0; i < locations.length(); i++) {
                JSONObject locationIterator = locations.getJSONObject(i);
                locationList.add(new VPNLocation(locationIterator.getString("label"),
                        locationIterator.getString("hostname")));
            }
            return locationList;
        } catch (JSONException je) {
            Log.e(LOG_TAG, je.toString());
            return null;
        } catch (IOException ioe) {
            Log.e(LOG_TAG, ioe.toString());
            return null;
        }
    }

    // Private worker method that actually communicates with the Privacy Online API.
    private JSONObject makeAPIRequest(String method, String endPoint, String jsonPayload)
            throws IOException, JSONException {
        InputStream inputStream = null;
        OutputStream outputStream = null;
        String apiUrl = "https://api.privacy.online";
        String apiKey = this.context.getString(R.string.privacy_online_api_key);
        String keyString = "?key=" + apiKey;

        int payloadSize = jsonPayload.length();

        try {
            URL url = new URL(apiUrl + endPoint + keyString);
            HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();

            // Sec 5 second connect/read timeouts
            connection.setReadTimeout(5000);
            connection.setConnectTimeout(5000);
            connection.setRequestMethod(method);
            connection.setRequestProperty("Content-Type", "application/json");

            if (payloadSize > 0) {
                connection.setDoInput(true);
                connection.setDoOutput(true);
                connection.setFixedLengthStreamingMode(payloadSize);
            }

            // Initiate the connection
            connection.connect();

            // Write the payload if there is one.
            if (payloadSize > 0) {
                outputStream = connection.getOutputStream();
                outputStream.write(jsonPayload.getBytes("UTF-8"));
            }

            // Get the response code ...
            int responseCode = connection.getResponseCode();
            Log.e(LOG_TAG, "Response code: " + responseCode);

            switch (responseCode) {
            case HttpsURLConnection.HTTP_OK:
                inputStream = connection.getInputStream();
                break;
            case HttpsURLConnection.HTTP_FORBIDDEN:
                inputStream = connection.getErrorStream();
                break;
            case HttpURLConnection.HTTP_NOT_FOUND:
                inputStream = connection.getErrorStream();
                break;
            case HttpsURLConnection.HTTP_UNAUTHORIZED:
                inputStream = connection.getErrorStream();
                break;
            default:
                inputStream = connection.getInputStream();
                break;
            }

            String responseContent = "{}"; // Default to an empty object.
            if (inputStream != null) {
                responseContent = readInputStream(inputStream, connection.getContentLength());
            }

            JSONObject responseObject = new JSONObject(responseContent);
            responseObject.put("code", responseCode);

            return responseObject;

        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
            if (outputStream != null) {
                outputStream.close();
            }
        }
    }

    // Util method for reading the IO stream in a buffered manner.
    private String readInputStream(InputStream inputStream, int contentLength) throws IOException {
        Reader reader = new InputStreamReader(inputStream, "UTF-8");
        char[] buffer = new char[contentLength];
        reader.read(buffer);
        return new String(buffer);
    }
}