Bangle.js: Add support for insecure TLS and HTTP requests

This commit is contained in:
José Rebelo
2025-05-21 20:48:39 +02:00
committed by José Rebelo
parent 73f13bce8c
commit 8c59fdbd5b
4 changed files with 123 additions and 7 deletions
+1
View File
@@ -121,6 +121,7 @@
android:fullBackupContent="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_round"
android:requestLegacyExternalStorage="true"
android:theme="@style/GadgetbridgeTheme"
@@ -157,6 +157,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
import nodomain.freeyourgadget.gadgetbridge.util.LimitedQueue;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
import nodomain.freeyourgadget.gadgetbridge.util.VolleyUtils;
public class BangleJSDeviceSupport extends AbstractBTLEDeviceSupport {
private static final Logger LOG = LoggerFactory.getLogger(BangleJSDeviceSupport.class);
@@ -190,6 +191,7 @@ public class BangleJSDeviceSupport extends AbstractBTLEDeviceSupport {
// used to make HTTP requests and handle responses
private RequestQueue requestQueue = null;
private RequestQueue insecureRequestQueue = null;
/// Maximum amount of characters to store in receiveHistory
public static final int MAX_RECEIVE_HISTORY_CHARS = 100000;
@@ -240,13 +242,32 @@ public class BangleJSDeviceSupport extends AbstractBTLEDeviceSupport {
if (requestQueue != null) {
requestQueue.stop();
}
if (insecureRequestQueue != null) {
insecureRequestQueue.stop();
}
}
private RequestQueue getRequestQueue() {
if (requestQueue == null) {
requestQueue = Volley.newRequestQueue(getContext());
private RequestQueue getRequestQueue(final boolean insecure) {
if (insecure) {
if (insecureRequestQueue == null) {
try {
insecureRequestQueue = Volley.newRequestQueue(
getContext(),
VolleyUtils.createInsecureHurlStack()
);
} catch (final Exception e) {
LOG.error("Failed to initialized insecure request queue", e);
// fallback to secure one
return getRequestQueue(false);
}
}
return insecureRequestQueue;
} else {
if (requestQueue == null) {
requestQueue = Volley.newRequestQueue(getContext());
}
return requestQueue;
}
return requestQueue;
}
private void addReceiveHistory(String s) {
@@ -886,7 +907,7 @@ public class BangleJSDeviceSupport extends AbstractBTLEDeviceSupport {
}
final String id = _id;
if (! BuildConfig.INTERNET_ACCESS) {
if (!BuildConfig.INTERNET_ACCESS) {
uartTxJSONError("http", "Internet access not enabled, check Gadgetbridge Device Settings", id);
return;
}
@@ -898,7 +919,7 @@ public class BangleJSDeviceSupport extends AbstractBTLEDeviceSupport {
}
String url = json.getString("url");
final boolean insecure = json.optBoolean("insecure", false);
int method = Request.Method.GET;
if (json.has("method")) {
String m = json.getString("method").toLowerCase(Locale.US);
@@ -1008,7 +1029,7 @@ public class BangleJSDeviceSupport extends AbstractBTLEDeviceSupport {
int timeout = json.getInt("timeout");
stringRequest.setRetryPolicy(new DefaultRetryPolicy(timeout, 0, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
}
RequestQueue queue = getRequestQueue();
RequestQueue queue = getRequestQueue(insecure);
queue.add(stringRequest);
}
@@ -2403,4 +2424,18 @@ public class BangleJSDeviceSupport extends AbstractBTLEDeviceSupport {
LOG.info("JSONException: " + e.getLocalizedMessage());
}
}
@Override
public void onTestNewFunction() {
try {
final JSONObject json = new JSONObject();
//json.put("t", "http");
//json.put("url", "https://example.com/");
//json.put("url", "https://192.168.1.2:4443");
//json.put("insecure", true);
//handleHttp(json);
} catch (final Exception e) {
LOG.error("Failed to test new function", e);
}
}
}
@@ -0,0 +1,71 @@
/* Copyright (C) 2025 José Rebelo
This file is part of Gadgetbridge.
Gadgetbridge is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gadgetbridge 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.util;
import android.annotation.SuppressLint;
import com.android.volley.toolbox.HurlStack;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class VolleyUtils {
public static HurlStack createInsecureHurlStack() throws Exception {
// Trust all certificates
final TrustManager[] trustAllCerts = new TrustManager[]{new InsecureTrustManager()};
final SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustAllCerts, new SecureRandom());
return new HurlStack(null, sslContext.getSocketFactory()) {
@Override
protected HttpURLConnection createConnection(final URL url) throws IOException {
final HttpURLConnection httpURLConnection = super.createConnection(url);
if (httpURLConnection instanceof HttpsURLConnection httpsURLConnection) {
// Trust all hostnames
httpsURLConnection.setHostnameVerifier((hostname, session) -> true);
}
return httpURLConnection;
}
};
}
@SuppressLint("CustomX509TrustManager")
public static class InsecureTrustManager implements X509TrustManager {
@SuppressLint("TrustAllX509TrustManager")
@Override
public void checkClientTrusted(final X509Certificate[] chain, final String authType) {
}
@SuppressLint("TrustAllX509TrustManager")
@Override
public void checkServerTrusted(final X509Certificate[] chain, final String authType) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
}
}
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" />
<certificates src="user" />
</trust-anchors>
</base-config>
</network-security-config>