mirror of
https://github.com/TrianguloY/UrlChecker.git
synced 2024-09-19 20:02:16 +02:00
Connection Wrapper
This commit is contained in:
parent
a4073e53b3
commit
fd52efd885
@ -2,20 +2,16 @@ package com.trianguloy.urlchecker.modules.companions;
|
||||
|
||||
import static android.util.Base64.NO_PADDING;
|
||||
import static android.util.Base64.NO_WRAP;
|
||||
import static android.util.Base64.URL_SAFE;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Base64;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.trianguloy.urlchecker.R;
|
||||
import com.trianguloy.urlchecker.utilities.methods.HttpUtils;
|
||||
import com.trianguloy.urlchecker.utilities.wrappers.Connection;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
@ -28,7 +24,7 @@ public class VirusTotalUtility {
|
||||
|
||||
static private final String URLS_ENDPOINT = "https://www.virustotal.com/api/v3/urls";
|
||||
|
||||
static public class InternalReponse {
|
||||
static public class InternalResponse {
|
||||
public String error = "Unknown error";
|
||||
public int detectionsPositive;
|
||||
public int detectionsTotal;
|
||||
@ -38,28 +34,23 @@ public class VirusTotalUtility {
|
||||
}
|
||||
|
||||
/** Returns the analysis of an url, or null if the analysis is in progress */
|
||||
public static InternalReponse scanUrl(String urlToScan, String key, Context cntx) {
|
||||
var result = new InternalReponse();
|
||||
public static InternalResponse scanUrl(String urlToScan, String key, Context cntx) {
|
||||
|
||||
// get analysis
|
||||
Pair<Integer, String> responsePair;
|
||||
try {
|
||||
responsePair = HttpUtils.readFromUrl(URLS_ENDPOINT + "/" + Base64.encodeToString(urlToScan.getBytes(), NO_PADDING | NO_WRAP), Map.of(
|
||||
"accept", "application/json",
|
||||
"x-apikey", key
|
||||
));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
result.error = cntx.getString(R.string.mVT_connectError);
|
||||
return result;
|
||||
}
|
||||
// connect
|
||||
var encodedUrl = Base64.encodeToString(urlToScan.getBytes(), NO_PADDING | NO_WRAP | URL_SAFE);
|
||||
var connection = Connection.to(URLS_ENDPOINT + "/" + encodedUrl)
|
||||
.addHeader("x-apikey", key)
|
||||
.acceptJson()
|
||||
.connect();
|
||||
|
||||
if (responsePair.first == 404) {
|
||||
if (connection.getStatusCode() == 404) {
|
||||
// not analyzed yet
|
||||
return analyzeUrl(urlToScan, key, cntx);
|
||||
}
|
||||
|
||||
if (responsePair.first != 200) {
|
||||
var result = new InternalResponse();
|
||||
var response = connection.getResultAsJson();
|
||||
if (response == null || connection.getStatusCode() != 200) {
|
||||
// error
|
||||
result.error = cntx.getString(R.string.mVT_jsonError);
|
||||
return result;
|
||||
@ -67,13 +58,11 @@ public class VirusTotalUtility {
|
||||
|
||||
// parse response
|
||||
try {
|
||||
JSONObject response = new JSONObject(responsePair.second);
|
||||
result.info = response.toString(1);
|
||||
var data = response.getJSONObject("data");
|
||||
result.scanUrl = data.getJSONObject("links").getString("self");
|
||||
result.scanUrl = "https://www.virustotal.com/gui/url/" + encodedUrl;
|
||||
|
||||
// parse attributes
|
||||
var attributes = data.getJSONObject("attributes");
|
||||
var attributes = response.getJSONObject("data").getJSONObject("attributes");
|
||||
|
||||
if (!attributes.has("last_analysis_date")) {
|
||||
// still analyzing
|
||||
@ -89,7 +78,6 @@ public class VirusTotalUtility {
|
||||
result.date = DateFormat.getInstance().format(new Date(attributes.getLong("last_analysis_date") * 1000));
|
||||
|
||||
result.error = null;
|
||||
return result;
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
result.error = cntx.getString(R.string.mVT_jsonError);
|
||||
@ -98,28 +86,23 @@ public class VirusTotalUtility {
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Requests an analysis (if not one already) */
|
||||
static private InternalReponse analyzeUrl(String urlToScan, String key, Context cntx) {
|
||||
try {
|
||||
var output = HttpUtils.performPOST(URLS_ENDPOINT, "url=" + URLEncoder.encode(urlToScan, "UTF-8"), Map.of(
|
||||
"accept", "application/json",
|
||||
"x-apikey", key,
|
||||
"content-type", "application/x-www-form-urlencoded"
|
||||
));
|
||||
/** Requests an analysis (if not done already) */
|
||||
static private InternalResponse analyzeUrl(String urlToScan, String key, Context cntx) {
|
||||
var code = Connection.to(URLS_ENDPOINT)
|
||||
.addHeader("x-apikey", key)
|
||||
.acceptJson()
|
||||
.postFormUrlEncoded(Map.of("url", urlToScan))
|
||||
.getStatusCode();
|
||||
|
||||
if (output.first != 200) {
|
||||
var result = new InternalReponse();
|
||||
result.error = cntx.getString(R.string.mVT_jsonError);
|
||||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
var result = new InternalReponse();
|
||||
if (code != 200) {
|
||||
// error
|
||||
var result = new InternalResponse();
|
||||
result.error = cntx.getString(R.string.mVT_jsonError);
|
||||
return result;
|
||||
}
|
||||
|
||||
// ok
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ import com.trianguloy.urlchecker.modules.companions.VirusTotalUtility;
|
||||
import com.trianguloy.urlchecker.url.UrlData;
|
||||
import com.trianguloy.urlchecker.utilities.generics.GenericPref;
|
||||
import com.trianguloy.urlchecker.utilities.methods.AndroidUtils;
|
||||
import com.trianguloy.urlchecker.utilities.methods.UrlUtils;
|
||||
import com.trianguloy.urlchecker.utilities.wrappers.DefaultTextWatcher;
|
||||
|
||||
/**
|
||||
@ -99,7 +98,7 @@ class VirusTotalDialog extends AModuleDialog {
|
||||
private TextView txt_result;
|
||||
|
||||
private boolean scanning = false;
|
||||
private VirusTotalUtility.InternalReponse result = null;
|
||||
private VirusTotalUtility.InternalResponse result = null;
|
||||
|
||||
private final GenericPref.Str api_key;
|
||||
|
||||
@ -155,7 +154,7 @@ class VirusTotalDialog extends AModuleDialog {
|
||||
* Manages the scanning in the background
|
||||
*/
|
||||
private void _scanUrl() {
|
||||
VirusTotalUtility.InternalReponse response;
|
||||
VirusTotalUtility.InternalResponse response;
|
||||
while (scanning) {
|
||||
// asks for the report
|
||||
response = VirusTotalUtility.scanUrl(getUrl(), api_key.get(), getActivity());
|
||||
@ -243,7 +242,8 @@ class VirusTotalDialog extends AModuleDialog {
|
||||
if (result == null || result.error != null) return;
|
||||
|
||||
if (details) {
|
||||
UrlUtils.openUrlRemoveThis(result.scanUrl, getActivity());
|
||||
setUrl(result.scanUrl);
|
||||
// UrlUtils.openUrlRemoveThis(result.scanUrl, getActivity());
|
||||
} else {
|
||||
// TODO: beautify this
|
||||
new AlertDialog.Builder(getActivity())
|
||||
|
@ -30,31 +30,4 @@ public interface UrlUtils {
|
||||
return intent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens an url removing this app from the chooser
|
||||
*
|
||||
* @param url url to open
|
||||
* @param cntx base context
|
||||
*/
|
||||
static void openUrlRemoveThis(String url, Context cntx) {
|
||||
|
||||
// get intents that can open the url
|
||||
List<Intent> intents = new ArrayList<>();
|
||||
for (var pack : IntentApp.getOtherPackages(getViewIntent(url, null), cntx)) {
|
||||
intents.add(getViewIntent(url, pack));
|
||||
}
|
||||
|
||||
// check if none
|
||||
if (intents.isEmpty()) {
|
||||
Toast.makeText(cntx, R.string.toast_noBrowser, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
// create chooser
|
||||
Intent chooserIntent = Intent.createChooser(intents.remove(0), cntx.getString(R.string.title_choose));
|
||||
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intents.toArray(new Parcelable[0]));
|
||||
|
||||
// open
|
||||
PackageUtils.startActivity(chooserIntent, R.string.toast_noBrowser, cntx);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,153 @@
|
||||
package com.trianguloy.urlchecker.utilities.wrappers;
|
||||
|
||||
import com.trianguloy.urlchecker.utilities.methods.StreamUtils;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
|
||||
/** Wrapper of HttpsURLConnection with some util methods */
|
||||
public class Connection {
|
||||
public static final int CONNECT_TIMEOUT = 5000;
|
||||
|
||||
/** Initializes a new connection to a specific url */
|
||||
public static Request to(String url) {
|
||||
return new Request(url);
|
||||
}
|
||||
|
||||
public static class Request {
|
||||
private HttpsURLConnection connection = null;
|
||||
|
||||
private Request(String url) {
|
||||
try {
|
||||
connection = (HttpsURLConnection) new URL(url).openConnection();
|
||||
connection.setConnectTimeout(CONNECT_TIMEOUT);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/** Adds a header to the connection */
|
||||
public Request addHeader(String header, String value) {
|
||||
if (connection == null) return this;
|
||||
connection.setRequestProperty(header, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Marks this request as accepting json */
|
||||
public Request acceptJson() {
|
||||
if (connection != null) connection.setRequestProperty("accept", "application/json");
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Connects and posts a string as body */
|
||||
public Response postString(String body) {
|
||||
if (connection == null) return new Response(null);
|
||||
|
||||
connection.setDoOutput(true);
|
||||
try (var writer = new OutputStreamWriter(connection.getOutputStream())) {
|
||||
writer.write(body);
|
||||
writer.flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
connection = null;
|
||||
}
|
||||
return new Response(connection);
|
||||
}
|
||||
|
||||
/** Connects and posts a key=value collection as body */
|
||||
public Response postFormUrlEncoded(Map<String, String> form) {
|
||||
if (connection == null) return new Response(null);
|
||||
|
||||
addHeader("content-type", "application/x-www-form-urlencoded");
|
||||
|
||||
try {
|
||||
var body = new StringBuilder();
|
||||
for (var param : form.entrySet()) {
|
||||
if (body.length() != 0) body.append('&');
|
||||
body.append(URLEncoder.encode(param.getKey(), "UTF-8"));
|
||||
body.append('=');
|
||||
body.append(URLEncoder.encode(param.getValue(), "UTF-8"));
|
||||
}
|
||||
return postString(body.toString());
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
return new Response(null);
|
||||
}
|
||||
}
|
||||
|
||||
/** Performs the connection */
|
||||
public Response connect() {
|
||||
if (connection == null) return new Response(null);
|
||||
try {
|
||||
connection.connect();
|
||||
return new Response(connection);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return new Response(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Response {
|
||||
private HttpsURLConnection connection;
|
||||
|
||||
private Response(HttpsURLConnection connection) {
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
/** Returns the status code, or -1 if something failed */
|
||||
public int getStatusCode() {
|
||||
if (connection == null) return -1;
|
||||
|
||||
try {
|
||||
return connection.getResponseCode();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
connection = null;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the result as string, or null if something failed */
|
||||
public String getResultAsString() {
|
||||
if (connection == null) return null;
|
||||
|
||||
try {
|
||||
return StreamUtils.inputStream2String(getStream());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
connection = null;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the result as json, or null if something failed */
|
||||
public JSONObject getResultAsJson() {
|
||||
var string = getResultAsString();
|
||||
if (string == null) return null;
|
||||
try {
|
||||
return new JSONObject(string);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
connection = null;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private InputStream getStream() throws IOException {
|
||||
return connection.getResponseCode() >= 200 && connection.getResponseCode() < 300
|
||||
? connection.getInputStream()
|
||||
: connection.getErrorStream();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user